Improve our parent/children identification with points, fix our testing that was failing with NULLs and asserted out. Added zone:check so that's its easier to identify parent for FTNs
This commit is contained in:
parent
247cf614f3
commit
541f612446
100
app/Console/Commands/ZoneCheck.php
Normal file
100
app/Console/Commands/ZoneCheck.php
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
|
use App\Models\{Domain};
|
||||||
|
use App\Models\Address;
|
||||||
|
use Illuminate\Console\Command;
|
||||||
|
|
||||||
|
class ZoneCheck extends Command
|
||||||
|
{
|
||||||
|
protected $signature = 'zone:check'
|
||||||
|
.' {domain : Domain Name}'
|
||||||
|
.' {--Z|zone= : Zone}';
|
||||||
|
|
||||||
|
protected $description = 'Check that the addresses in a zone are configured correctly';
|
||||||
|
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
$do = Domain::where('name',$this->argument('domain'))->singleOrFail();
|
||||||
|
|
||||||
|
foreach ($do->zones as $zo) {
|
||||||
|
if ($this->option('zone') && ($this->option('zone') != $zo->zone_id))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
$this->warn('Zone: '.$zo->zone_id);
|
||||||
|
$this->info(sprintf('- Our address(es): %s',our_address($zo)->pluck('ftn4d')->join(',')));
|
||||||
|
|
||||||
|
$this->table(['id','ftn','role','parent','region_id','host_id','hub_id','system','notes'],$zo->addresses()->FTNorder()->active()->with(['system'])->get()->transform(function($item) {
|
||||||
|
return [
|
||||||
|
'id'=>$item->id,
|
||||||
|
'ftn'=>$item->ftn4d,
|
||||||
|
'role'=>$item->role_name,
|
||||||
|
'parent'=>$item->parent()?->ftn4d,
|
||||||
|
'region_id'=>$item->region_id,
|
||||||
|
'host_id'=>$item->host_id,
|
||||||
|
'hub_id'=>$item->hub_id,
|
||||||
|
'system'=>$item->system->name,
|
||||||
|
'notes'=>$this->check($item),
|
||||||
|
];
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Command::SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check that an address is defined correctly
|
||||||
|
*
|
||||||
|
* @param Address $ao
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function check(Address $ao): string
|
||||||
|
{
|
||||||
|
// ZC address
|
||||||
|
if ($ao->role === Address::NODE_ZC) {
|
||||||
|
if (($ao->region_id === 0) && ($ao->host_id === 0) && ($ao->node_id === 0) && is_null($ao->hub_id) && ($ao->point_id === 0))
|
||||||
|
return 'OK';
|
||||||
|
|
||||||
|
else
|
||||||
|
return 'INVALID ZC address';
|
||||||
|
}
|
||||||
|
|
||||||
|
// RC address
|
||||||
|
if ($ao->role === Address::NODE_RC) {
|
||||||
|
if ($ao->region_id && ($ao->region_id === $ao->host_id) && ($ao->node_id === 0) && is_null($ao->hub_id) && ($ao->point_id === 0))
|
||||||
|
return 'OK';
|
||||||
|
else
|
||||||
|
return 'INVALID RC address';
|
||||||
|
}
|
||||||
|
|
||||||
|
// NC address
|
||||||
|
if ($ao->role === Address::NODE_NC) {
|
||||||
|
if (($ao->node_id !== 0) && is_null($ao->hub_id) && ($ao->point_id === 0))
|
||||||
|
return 'OK';
|
||||||
|
else
|
||||||
|
return 'INVALID NC address';
|
||||||
|
}
|
||||||
|
|
||||||
|
// HUB address
|
||||||
|
if ($ao->role === Address::NODE_HC) {
|
||||||
|
if (($ao->node_id !== 0) && is_null($ao->hub_id) && ($ao->point_id === 0))
|
||||||
|
return 'OK';
|
||||||
|
else
|
||||||
|
return 'INVALID HUB address';
|
||||||
|
}
|
||||||
|
|
||||||
|
// POINT address
|
||||||
|
if ($ao->role === Address::NODE_POINT) {
|
||||||
|
if ($ao->point_id !== 0)
|
||||||
|
return 'OK';
|
||||||
|
else
|
||||||
|
return 'INVALID POINT address';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($ao->region_id && ($ao->host_id === 0))
|
||||||
|
return 'INVALID REGION NODE';
|
||||||
|
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
@ -150,7 +150,6 @@ class Address extends Model
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Find children dependent on this record
|
* Find children dependent on this record
|
||||||
* @todo If bosses are defined here, and points, then mail to a point goes to it's boss
|
|
||||||
*/
|
*/
|
||||||
public function children()
|
public function children()
|
||||||
{
|
{
|
||||||
@ -194,9 +193,18 @@ class Address extends Model
|
|||||||
case self::NODE_PVT:
|
case self::NODE_PVT:
|
||||||
case self::NODE_HOLD:
|
case self::NODE_HOLD:
|
||||||
case self::NODE_DOWN:
|
case self::NODE_DOWN:
|
||||||
case self::NODE_POINT:
|
|
||||||
case self::NODE_UNKNOWN:
|
case self::NODE_UNKNOWN:
|
||||||
// Nodes dont have children, but must return a relationship instance
|
// Identify our children.
|
||||||
|
$children = self::select('addresses.*')
|
||||||
|
->where('zone_id',$this->zone_id)
|
||||||
|
->where('region_id',$this->region_id)
|
||||||
|
->where('host_id',$this->host_id)
|
||||||
|
->where('node_id',$this->node_id)
|
||||||
|
->where('point_id','<>',0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case self::NODE_POINT:
|
||||||
|
// Points dont have children, but must return a relationship instance
|
||||||
return $this->hasOne(self::class,NULL,'void');
|
return $this->hasOne(self::class,NULL,'void');
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -298,14 +306,17 @@ class Address extends Model
|
|||||||
*
|
*
|
||||||
* @return Address|null
|
* @return Address|null
|
||||||
* @throws \Exception
|
* @throws \Exception
|
||||||
* @todo Dont include points in this
|
|
||||||
*/
|
*/
|
||||||
public function parent(): ?Address
|
public function parent(): ?Address
|
||||||
{
|
{
|
||||||
// If we are have session password, then we dont have a parent
|
// If we have session password, then we are the parent
|
||||||
if ($this->session('sespass'))
|
if ($this->session('sespass'))
|
||||||
return $this;
|
return $this;
|
||||||
|
|
||||||
|
// If it is our address
|
||||||
|
if (our_address()->contains($this))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
switch ($this->role) {
|
switch ($this->role) {
|
||||||
// ZCs dont have parents, but we may have a default
|
// ZCs dont have parents, but we may have a default
|
||||||
case self::NODE_ZC:
|
case self::NODE_ZC:
|
||||||
@ -326,15 +337,15 @@ class Address extends Model
|
|||||||
|
|
||||||
// Hosts
|
// Hosts
|
||||||
case self::NODE_NC:
|
case self::NODE_NC:
|
||||||
// See if we have a RC
|
// See if we have an RC
|
||||||
$parent = self::where('zone_id',$this->zone_id)
|
$parent = self::where('zone_id',$this->zone_id)
|
||||||
->where('region_id',$this->region_id)
|
->where('region_id',$this->region_id)
|
||||||
->where('host_id',0)
|
->where('host_id',$this->region_id)
|
||||||
->where('node_id',0)
|
->where('node_id',0)
|
||||||
->single();
|
->single();
|
||||||
|
|
||||||
if (! $parent) {
|
if (! $parent) {
|
||||||
// See if we have a RC
|
// See if we have an ZC
|
||||||
$parent = self::where('zone_id',$this->zone_id)
|
$parent = self::where('zone_id',$this->zone_id)
|
||||||
->where('region_id',0)
|
->where('region_id',0)
|
||||||
->where('host_id',0)
|
->where('host_id',0)
|
||||||
@ -351,22 +362,27 @@ class Address extends Model
|
|||||||
case self::NODE_PVT:
|
case self::NODE_PVT:
|
||||||
case self::NODE_HOLD:
|
case self::NODE_HOLD:
|
||||||
case self::NODE_DOWN:
|
case self::NODE_DOWN:
|
||||||
|
case self::NODE_UNKNOWN:
|
||||||
// If we are a child of a hub, then check our hub
|
// If we are a child of a hub, then check our hub
|
||||||
$parent = ($this->hub_id
|
$parent = ($this->hub_id
|
||||||
? self::where('id',$this->hub_id)
|
? self::where('id',$this->hub_id)
|
||||||
: self::where('zone_id',$this->zone_id)
|
: self::where('zone_id',$this->zone_id)
|
||||||
->where('region_id',$this->region_id)
|
->where('region_id',$this->region_id)
|
||||||
->where('host_id',$this->host_id)
|
->where('host_id',$this->host_id)
|
||||||
->where('node_id',0)
|
->where('role','<',self::NODE_HC))
|
||||||
->where('role','<',$this->role))
|
->active()
|
||||||
->single();
|
->single();
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case self::NODE_UNKNOWN:
|
|
||||||
case self::NODE_POINT:
|
case self::NODE_POINT:
|
||||||
// @todo Points - if the boss is defined, we should return it.
|
$parent = self::where('zone_id',$this->zone_id)
|
||||||
return NULL;
|
->where('region_id',$this->region_id)
|
||||||
|
->where('host_id',$this->host_id)
|
||||||
|
->where('node_id',$this->node_id)
|
||||||
|
->where('point_id',0)
|
||||||
|
->active()
|
||||||
|
->single();
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new \Exception(sprintf('Unknown role: %s (%d)',serialize($this->role),$this->id));
|
throw new \Exception(sprintf('Unknown role: %s (%d)',serialize($this->role),$this->id));
|
||||||
|
@ -190,7 +190,7 @@ class TestNodeHierarchy extends Seeder
|
|||||||
'validated'=>TRUE,
|
'validated'=>TRUE,
|
||||||
'region_id'=>$rid,
|
'region_id'=>$rid,
|
||||||
'host_id'=>$hostid,
|
'host_id'=>$hostid,
|
||||||
'node_id'=>0,
|
'node_id'=>7,
|
||||||
'point_id'=>0,
|
'point_id'=>0,
|
||||||
'system_id'=>$so->id,
|
'system_id'=>$so->id,
|
||||||
'role'=>Address::NODE_NC,
|
'role'=>Address::NODE_NC,
|
||||||
|
@ -6,8 +6,48 @@ use Illuminate\Database\Eloquent\Collection;
|
|||||||
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||||
use Tests\TestCase;
|
use Tests\TestCase;
|
||||||
|
|
||||||
use App\Models\{Address,Domain,Setup};
|
use App\Models\{Address,Domain,Setup,System};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Here we test mail routing.
|
||||||
|
*
|
||||||
|
* - COMMON to all routing nodes
|
||||||
|
* + We have RCs defined - everything for a node in the Region goes to an RC, unless RC's node defined locally, or nodes assigned to ZC
|
||||||
|
* ie: region_id is the same, find the NC/HUB/NODE address for the system_id that has been assigned 0/0 in the same region.
|
||||||
|
* nodes assigned to ZC have region_id = 0. Nodes with hub_id = NULL and host_id=0 are RC nodes.
|
||||||
|
* + We have NCs defined - everything under the Host goes to the NC, unless NC's nodes defined locally or nodes assigned to the RC
|
||||||
|
* ie: node_id defines the NCs responsible. Nodes with hub_id = NULL are an NC node.
|
||||||
|
* + We have HUBs defined - everything under the Hub goes to the HUB, unless HUB's nodes defined locally
|
||||||
|
* ie: hub_id defines who the hub is.
|
||||||
|
* + We have NODES defined - mail collected locally, including mail for it's point
|
||||||
|
*
|
||||||
|
* - Routing scenarios:
|
||||||
|
* - We are ZC for a domain
|
||||||
|
* + See COMMON
|
||||||
|
* + Everything else is collected locally
|
||||||
|
*
|
||||||
|
* - We are RC for a domain
|
||||||
|
* + See COMMON
|
||||||
|
* + Any nodes in our RC not defined with an NC is collected locally, including points
|
||||||
|
* + Everything else is sent to the ZC (our uplink)
|
||||||
|
*
|
||||||
|
* - We are NC for a domain
|
||||||
|
* + See COMMON
|
||||||
|
* + Any nodes in our NC not defined with a HUB is collected locally, including points
|
||||||
|
* + Everything else is sent to the RC or ZC (our uplink)
|
||||||
|
*
|
||||||
|
* - We are a Hub for a domain
|
||||||
|
* + See COMMON
|
||||||
|
* + Any nodes in our HUB is collected locally, including points
|
||||||
|
* + Everything else is sent to the NC or RC (our uplink)
|
||||||
|
*
|
||||||
|
* - We are a Node in a domain
|
||||||
|
* + See COMMON
|
||||||
|
* + Everything else is sent to the HUB or Host or RC (our uplink)
|
||||||
|
*
|
||||||
|
* @see Address::parent()
|
||||||
|
* @see Address::children()
|
||||||
|
*/
|
||||||
class RoutingTest extends TestCase
|
class RoutingTest extends TestCase
|
||||||
{
|
{
|
||||||
use DatabaseTransactions;
|
use DatabaseTransactions;
|
||||||
@ -38,7 +78,7 @@ class RoutingTest extends TestCase
|
|||||||
private function session_nc(): void
|
private function session_nc(): void
|
||||||
{
|
{
|
||||||
// Add session info, and we have 51 children
|
// Add session info, and we have 51 children
|
||||||
$ao = Address::findFTN('100:10/0@a');
|
$ao = Address::findFTN('100:10/7@a');
|
||||||
$ao->system->sessions()->attach([$ao->zone_id=>['sespass'=>'ABCD']]);
|
$ao->system->sessions()->attach([$ao->zone_id=>['sespass'=>'ABCD']]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,8 +133,17 @@ class RoutingTest extends TestCase
|
|||||||
$this->assertEquals('101:0/0.0@a',$ao->parent()->ftn);
|
$this->assertEquals('101:0/0.0@a',$ao->parent()->ftn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get a list of active addresses in a Region
|
||||||
|
public function test_rc_session_children()
|
||||||
|
{
|
||||||
|
$this->session_rc();
|
||||||
|
|
||||||
|
$ao = Address::findFTN('100:1/0@a');
|
||||||
|
$this->assertEquals(185,$ao->children()->count());
|
||||||
|
}
|
||||||
|
|
||||||
// An RCs node still collects mail from the RC
|
// An RCs node still collects mail from the RC
|
||||||
public function test_zc_rc_node_rc()
|
public function test_rc_node_rc()
|
||||||
{
|
{
|
||||||
$this->session_rc();
|
$this->session_rc();
|
||||||
|
|
||||||
@ -105,58 +154,45 @@ class RoutingTest extends TestCase
|
|||||||
}
|
}
|
||||||
|
|
||||||
// An NC collects mail for its children
|
// An NC collects mail for its children
|
||||||
public function test_zc_nc_node_rc()
|
public function test_rc_nc_node_rc()
|
||||||
{
|
{
|
||||||
return $this->assertTrue(TRUE);
|
|
||||||
$this->session_rc();
|
$this->session_rc();
|
||||||
|
|
||||||
// A NCs parent should still be the RC
|
// A NCs parent should still be the RC
|
||||||
$ao = Address::findFTN('100:10/0@a');
|
$ao = Address::findFTN('100:10/7@a');
|
||||||
$this->assertEquals($ao->role,Address::NODE_NC);
|
$this->assertEquals($ao->role,Address::NODE_NC);
|
||||||
$this->assertEquals('100:1/0.0@a',$ao->parent()->ftn); // @todo fails, returning NULL?
|
$this->assertEquals('100:1/0.0@a',$ao->parent()->ftn);
|
||||||
}
|
}
|
||||||
|
|
||||||
// A Hub still collects mail from NC
|
// A Hub still collects mail from NC
|
||||||
public function test_zc_hub_node_nc()
|
public function test_rc_hub_node_nc()
|
||||||
{
|
{
|
||||||
return $this->assertTrue(TRUE);
|
|
||||||
$this->session_rc();
|
$this->session_rc();
|
||||||
|
|
||||||
// A Hubs parent should still be the NC
|
// A Hubs parent should still be the NC
|
||||||
$ao = Address::findFTN('100:10/20.0@a');
|
$ao = Address::findFTN('100:10/20.0@a');
|
||||||
$this->assertEquals($ao->role,Address::NODE_HC);
|
$this->assertEquals($ao->role,Address::NODE_HC);
|
||||||
$this->assertEquals('100:1/0.0@a',$ao->parent()->ftn); // @todo fails, returning NULL?
|
$this->assertEquals('100:1/0.0@a',$ao->parent()->ftn);
|
||||||
}
|
}
|
||||||
|
|
||||||
// A Hub's node still collects mail from Hub
|
// A Hub's node still collects mail from Hub
|
||||||
public function test_zc_hub_node_hub()
|
public function test_rc_hub_node_hub()
|
||||||
{
|
{
|
||||||
return $this->assertTrue(TRUE);
|
|
||||||
$this->session_rc();
|
$this->session_rc();
|
||||||
|
|
||||||
// A Hubs node should still be the Hub
|
// A Hubs node should still be the Hub
|
||||||
$ao = Address::findFTN('100:10/22.0@a');
|
$ao = Address::findFTN('100:10/22.0@a');
|
||||||
$this->assertEquals($ao->role,Address::NODE_ACTIVE);
|
$this->assertEquals($ao->role,Address::NODE_ACTIVE);
|
||||||
$this->assertEquals('100:1/0.0@a',$ao->parent()->ftn); // @todo fails, returning NULL?
|
$this->assertEquals('100:1/0.0@a',$ao->parent()->ftn);
|
||||||
}
|
|
||||||
|
|
||||||
// When we have an RC with session details, we route to all its children
|
|
||||||
public function test_rc_session_children()
|
|
||||||
{
|
|
||||||
$this->session_rc();
|
|
||||||
|
|
||||||
$ao = Address::findFTN('100:1/0@a');
|
|
||||||
$this->assertCount(185,$ao->children);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// An RCs parent is us even if we have session details for another RC
|
// An RCs parent is us even if we have session details for another RC
|
||||||
public function test_rc_parent()
|
public function test_rc_parent()
|
||||||
{
|
{
|
||||||
return $this->assertTrue(TRUE);
|
|
||||||
$this->session_rc();
|
$this->session_rc();
|
||||||
|
|
||||||
$ao = Address::findFTN('100:2/0@a');
|
$ao = Address::findFTN('100:2/0@a');
|
||||||
$this->assertEquals('100:0/0.0@a',$ao->parent()->ftn); // @todo fails, returning NULL?
|
$this->assertNull($ao->parent()?->ftn);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we also have session details for an NC, then there are less RC nodes
|
// If we also have session details for an NC, then there are less RC nodes
|
||||||
@ -164,7 +200,7 @@ class RoutingTest extends TestCase
|
|||||||
{
|
{
|
||||||
$this->session_rc();
|
$this->session_rc();
|
||||||
|
|
||||||
$ao = Address::findFTN('100:10/0@a');
|
$ao = Address::findFTN('100:10/7@a');
|
||||||
$ao->system->sessions()->attach([$ao->zone_id=>['sespass'=>'ABCD']]);
|
$ao->system->sessions()->attach([$ao->zone_id=>['sespass'=>'ABCD']]);
|
||||||
|
|
||||||
$ao = Address::findFTN('100:1/0@a');
|
$ao = Address::findFTN('100:1/0@a');
|
||||||
@ -185,6 +221,7 @@ class RoutingTest extends TestCase
|
|||||||
$ao = Address::findFTN('100:10/22@a');
|
$ao = Address::findFTN('100:10/22@a');
|
||||||
$this->assertEquals('100:10/20.0@a',$ao->parent()->ftn);
|
$this->assertEquals('100:10/20.0@a',$ao->parent()->ftn);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we also have session details for an Hub, then there are less RC nodes
|
// If we also have session details for an Hub, then there are less RC nodes
|
||||||
public function test_rc_hub_session_child()
|
public function test_rc_hub_session_child()
|
||||||
{
|
{
|
||||||
@ -193,4 +230,40 @@ class RoutingTest extends TestCase
|
|||||||
$ao = Address::findFTN('100:10/22@a');
|
$ao = Address::findFTN('100:10/22@a');
|
||||||
$this->assertEquals('100:10/20.0@a',$ao->parent()->ftn);
|
$this->assertEquals('100:10/20.0@a',$ao->parent()->ftn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// When we have an RC with session details, we route to all its children
|
||||||
|
public function test_nc_session_children()
|
||||||
|
{
|
||||||
|
$this->session_nc();
|
||||||
|
|
||||||
|
$ao = Address::findFTN('100:10/7@a');
|
||||||
|
$this->assertCount(35,$ao->children);
|
||||||
|
}
|
||||||
|
|
||||||
|
// A points parent is the node, if we have traffic for a point and we have session details for the node
|
||||||
|
public function test_point_session_node()
|
||||||
|
{
|
||||||
|
//$this->session_hub();
|
||||||
|
|
||||||
|
$so = new System;
|
||||||
|
$so->name = 'Point System';
|
||||||
|
$so->sysop = 'Point Sysop';
|
||||||
|
$so->location = 'Melbourne, AU';
|
||||||
|
$so->active = TRUE;
|
||||||
|
$so->save();
|
||||||
|
|
||||||
|
// Create a child
|
||||||
|
$ao = Address::createFTN('100:10/21.2@a',$so);
|
||||||
|
$ao->region_id = 1; // @todo This should be worked out from the parent node (if exists), or another node on the same host
|
||||||
|
$ao->save();
|
||||||
|
|
||||||
|
$ao = Address::findFTN('100:10/21.0@a');
|
||||||
|
$ao->system->sessions()->attach([$ao->zone_id=>['sespass'=>'ABCD']]);
|
||||||
|
|
||||||
|
$ao = Address::findFTN('100:10/21.2@a');
|
||||||
|
$this->assertEquals('100:10/21.0@a',$ao->parent()?->ftn);
|
||||||
|
|
||||||
|
$ao = Address::findFTN('100:10/21@a');
|
||||||
|
$this->assertCount(1,$ao->children);
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user