More work to decommission rogue_path

This commit is contained in:
Deon George 2023-09-15 22:57:32 +10:00
parent c1d6d48a3c
commit 708d9a9f67
12 changed files with 218 additions and 231 deletions

View File

@ -12,7 +12,7 @@ use Illuminate\Validation\Validator as ValidatorResult;
use App\Classes\FTN as FTNBase;
use App\Http\Controllers\DomainController;
use App\Models\{Address,Domain,Zone};
use App\Models\{Address,Domain,System,Zone};
use App\Rules\{TwoByteInteger,TwoByteIntegerWithZero};
use App\Traits\EncodeUTF8;
@ -139,10 +139,9 @@ class Message extends FTNBase
private Collection $rescanned; // Message was created as a result of a rescan
private Collection $path; // FTS-0004.001 The message PATH lines
private Collection $pathaddress; // Collection of Addresses after parsing seenby
private Collection $rogue_path; // Collection of FTNs in the Seen-by that are not defined
private Collection $rogue_seenby; // Collection of FTNs in the Seen-by that are not defined
private Collection $seenby; // FTS-0004.001 The message SEEN-BY lines
private Collection $seenaddress; // Collection of Addresses after parsing seenby
private Collection $rogue_seenby; // Collection of FTNs in the Seen-by that are not defined
private Collection $via; // The path the message has gone using Via lines (Netmail)
private Collection $unknown; // Temporarily hold attributes we have no logic for.
@ -225,11 +224,10 @@ class Message extends FTNBase
$this->kludge = collect();
$this->rescanned = collect();
$this->path = collect();
$this->rogue_seenby = collect();
$this->seenby = collect();
$this->seenaddress = collect();
$this->pathaddress = collect();
$this->rogue_seenby = collect();
$this->rogue_path = collect();
$this->via = collect();
$this->unknown = collect();
}
@ -367,9 +365,8 @@ class Message extends FTNBase
case 'path':
case 'seenby':
case 'pathaddress':
case 'seenaddress':
case 'rogue_path':
case 'rogue_seenby':
case 'seenaddress':
case 'unknown':
case 'via':
@ -697,46 +694,47 @@ class Message extends FTNBase
$node = (int)$item;
}
$aoid = NULL;
// If domain should be flattened, look for node regardless of zone (within the list of zones for the domain)
if ($this->fdomain && $this->fdomain->flatten) {
$ao = Address::findZone($this->fdomain,$net&DomainController::NUMBER_MAX,$node&DomainController::NUMBER_MAX,0);
$ftn = sprintf('%d:%d/%d@%s',$this->fz,$net&DomainController::NUMBER_MAX,$node&DomainController::NUMBER_MAX,$this->fdomain->name);
$ftn = sprintf('%d:%d/%d@%s',0,$net&DomainController::NUMBER_MAX,$node&DomainController::NUMBER_MAX,$this->fdomain->name);
$aoid = $ao?->id;
} elseif ($this->fdomain) {
$ftn = sprintf('%d:%d/%d@%s',$this->fz,$net&DomainController::NUMBER_MAX,$node&DomainController::NUMBER_MAX,$this->fdomain->name);
} else {
$ftn = sprintf('%d:%d/%d',$this->fz,$net&DomainController::NUMBER_MAX,$node&DomainController::NUMBER_MAX);
$aoid = NULL;
}
switch ($type) {
case 'path':
if (! $aoid) {
$ao = (Address::findFTN($ftn,TRUE));
$aoid = $ao?->id;
}
break;
case 'seenby':
if (! $aoid) {
$ao = (Address::findFTN($ftn));
$aoid = $ao?->id;
}
break;
default:
throw new \Exception('Unknown type: '.$type);
}
if (! $aoid) {
Log::alert(sprintf('%s:! Undefined Node [%s] in [%s].',self::LOGKEY,$ftn,$type));
$rogue->push($ftn);
if (! ($ao=Address::findFTN($ftn))) {
Log::alert(sprintf('%s:! Undefined Node [%s] in [%s] - auto created.',self::LOGKEY,$ftn,$type));
} else {
$nodes->push($aoid);
$ao = Address::createFTN($ftn,System::createUnknownSystem());
}
$aoid = $ao?->id;
}
switch ($type) {
case 'seenby':
if (! $ao) {
$rogue->push(sprintf('%d:%d/%d',$this->fz,$net&DomainController::NUMBER_MAX,$node&DomainController::NUMBER_MAX));
continue 2;
}
case 'path':
if (! $aoid)
throw new \Exception(sprintf('Didnt get an address for [%s]',$ftn));
break;
}
$nodes->push($aoid);
}
}
@ -793,11 +791,10 @@ class Message extends FTNBase
* <FTN Address> @YYYYMMDD.HHMMSS[.Precise][.Time Zone] <Program Name> <Version> [Serial Number]
*
* @param Collection $via
* @param Collection $rogue
* @return Collection
* @throws \Exception
*/
private function parseVia(Collection $via,Collection &$rogue): Collection
private function parseVia(Collection $via): Collection
{
$nodes = collect();
@ -1017,13 +1014,14 @@ class Message extends FTNBase
if ($this->seenby->count())
$this->seenaddress = $this->parseAddresses('seenby',$this->seenby,$this->rogue_seenby);
$dummy = collect();
// Parse PATH
if ($this->path->count())
$this->pathaddress = $this->parseAddresses('path',$this->path,$this->rogue_path);
$this->pathaddress = $this->parseAddresses('path',$this->path,$dummy);
// Parse VIA
if ($this->via->count())
$this->pathaddress = $this->parseVia($this->via,$this->rogue_path);
$this->pathaddress = $this->parseVia($this->via);
}
/**

View File

@ -449,14 +449,8 @@ class Packet extends FTNBase implements \Iterator, \Countable
$ao->role = Address::NODE_UNKNOWN;
System::unguard();
$so = System::firstOrCreate([
'name' => 'Discovered System',
'sysop' => 'Unknown',
'location' => '',
'active' => TRUE,
]);
System::reguard();
$so = System::createUnknownSystem();
// @todo Remove this debugging line
if ($so->id !== 443)
Log::alert(sprintf('%s:? Just created Discovered System for MSGID [%s] A',self::LOGKEY,$msg->msgid));
@ -490,14 +484,8 @@ class Packet extends FTNBase implements \Iterator, \Countable
$ao->role = Address::NODE_UNKNOWN;
System::unguard();
$so = System::firstOrCreate([
'name' => 'Discovered System',
'sysop' => 'Unknown',
'location' => '',
'active' => TRUE,
]);
System::reguard();
$so = System::createUnknownSystem();
// @todo Remvoe this debugging line
if ($so->id !== 443)
Log::alert(sprintf('%s:? Just created Discovered System for MSGID [%s] B',self::LOGKEY,$msg->msgid));

View File

@ -10,7 +10,7 @@ use Illuminate\Support\Facades\Storage;
use League\Flysystem\UnableToWriteFile;
use App\Classes\FTN as FTNBase;
use App\Models\{Address,File,Filearea,Setup};
use App\Models\{Address,File,Filearea,Setup,System};
use App\Traits\EncodeUTF8;
/**
@ -67,7 +67,6 @@ class Tic extends FTNBase
$this->fo->kludges = collect();
$this->fo->set_path = collect();
$this->fo->set_seenby = collect();
$this->fo->rogue_path = collect();
$this->fo->rogue_seenby = collect();
$this->values = collect();
@ -240,22 +239,23 @@ class Tic extends FTNBase
preg_match(sprintf('#^[Pp]ath (%s)\ ?([0-9]+)\ ?(.*)$#',Address::ftn_regex),$line,$x);
$ao = Address::findFTN($x[1]);
if (! $ao) {
$this->fo->rogue_path->push($matches[2]);
} else {
$this->fo->set_path->push(['address'=>$ao,'datetime'=>Carbon::createFromTimestamp($x[8]),'extra'=>$x[9]]);
}
if (! $ao)
$ao = Address::createFTN($x[1],System::createUnknownSystem());
$this->fo->set_path->push(['address'=>$ao,'datetime'=>Carbon::createFromTimestamp($x[8]),'extra'=>$x[9]]);
break;
case 'seenby':
$ao = Address::findFTN($matches[2]);
if (! $ao) {
if (! $ao)
$ao = Address::createFTN($x[1],System::createUnknownSystem());
if (! $ao)
$this->fo->rogue_seenby->push($matches[2]);
} else {
else
$this->fo->set_seenby->push($ao->id);
}
break;
}

View File

@ -429,17 +429,14 @@ abstract class Protocol
));
// Add unknown FTNs to the DB
if ($this->node->aka_remote_authed->count()) {
$so = $this->node->aka_remote_authed->first()->system;
} else {
$so = System::where('name','Discovered System')->first();
}
$so = ($this->node->aka_remote_authed->count())
? $this->node->aka_remote_authed->first()->system
: System::createUnknownSystem();
if ($so && $so->exists) {
foreach ($this->node->aka_other as $aka) {
Address::findFTN($aka,TRUE,$so);
}
foreach ($this->node->aka_other as $aka)
if (! Address::findFTN($aka))
Address::createFTN($aka,$so);
// Log session in DB
$slo = new SystemLog;

View File

@ -685,7 +685,7 @@ final class Binkp extends BaseProtocol
while ($rem_aka=$this->strsep($buf,' ')) {
try {
if (! ($o=Address::findFTN($rem_aka,FALSE,NULL,TRUE))) {
if (! ($o=Address::findFTN($rem_aka,TRUE))) {
// @todo when we have multiple inactive records, this returns more than 1, so pluck the active record if there is one
Log::alert(sprintf('%s:? AKA is UNKNOWN [%s]',self::LOGKEY,$rem_aka));

View File

@ -6,7 +6,7 @@ use Illuminate\Console\Command;
use Illuminate\Database\QueryException;
use Illuminate\Support\Facades\DB;
use App\Models\Address;
use App\Models\{Address,System};
class AddressMerge extends Command
{
@ -39,7 +39,7 @@ class AddressMerge extends Command
$src = Address::withTrashed()->findOrfail($this->argument('src'));
$dst = Address::withTrashed()->findOrfail($this->argument('dst'));
if ((! $this->option('ignore')) && ($src->system_id !== $dst->system_id) && ($src->system->name !== 'Discovered System')) {
if ((! $this->option('ignore')) && ($src->system_id !== $dst->system_id) && ($src->system->name !== System::default)) {
$this->error(sprintf('FTN addresses are from different systems (%s/%s)',$src->system->name,$dst->system->name));
exit(1);
}

View File

@ -6,7 +6,7 @@ use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Gate;
use App\Models\Address;
use App\Models\{Address,System};
class AddressMerge extends FormRequest
{
@ -35,7 +35,7 @@ class AddressMerge extends FormRequest
$dst = Address::withTrashed()->findOrFail($value);
$src = Address::withTrashed()->findOrFail($request->src);
if ((! $dst->active) && ($dst->system_id !== $src->system_id) && ($src->system->name !== 'Discovered System'))
if ((! $dst->active) && ($dst->system_id !== $src->system_id) && ($src->system->name !== System::default))
$fail('Destination must be active, or be from the system system');
},
function ($attribute,$value,$fail) use ($request) {

View File

@ -325,7 +325,6 @@ class MessageProcess implements ShouldQueue
$o->msg_src = $this->msg->message_src;
$o->msg_crc = md5($this->msg->message);
$o->rogue_seenby = $this->msg->rogue_seenby;
$o->rogue_path = $this->msg->rogue_path;
$o->set_path = $this->msg->pathaddress;
$o->set_seenby = $this->msg->seenaddress;
$o->set_recvtime = $this->recvtime;

View File

@ -351,7 +351,7 @@ class NodelistImport implements ShouldQueue
}
// If the address exists, but it was discovered, assign it to this new host
if ($ao->system_id && ($ao->system_id !== $so->id) && ($ao->system->name === 'Discovered System')) {
if ($ao->system_id && ($ao->system_id !== $so->id) && ($ao->system->name === System::default)) {
Log::info(sprintf('%s:= Re-assigning discovered address to [%s]',self::LOGKEY,$so->id));
} elseif (! $ao->system_id) {

View File

@ -372,6 +372,99 @@ class Address extends Model
/* METHODS */
/**
* Create an FTN address associated with a system
*
* @param string $address
* @param System $so
* @return self
* @throws \Exception
*/
public static function createFTN(string $address,System $so): ?self
{
$ftn = self::parseFTN($address);
if (! $ftn['d']) {
// See if we have a default domain for this domain
if ($ftn['z']) {
$zo = Zone::where('zone_id',$ftn['z'])->where('default',TRUE)->single();
if ($zo)
$ftn['d'] = $zo->domain->name;
else {
Log::alert(sprintf('%s:! Refusing to create address [%s] no domain available',self::LOGKEY,$address));
return NULL;
}
}
}
Log::debug(sprintf('%s:- Creating AKA [%s] for [%s]',self::LOGKEY,$address,$so->name));
// Check Domain exists
Domain::unguard();
$do = Domain::singleOrNew(['name'=>$ftn['d']]);
Domain::reguard();
if (! $do->exists) {
$do->public = TRUE;
$do->active = TRUE;
$do->notes = 'Auto created';
$do->save();
}
// If the zone is zero, see if this is a flatten domain, and if so, find an NC
if (($ftn['z'] === 0) && $do->flatten) {
$nc = self::findZone($do,$ftn['n'],0,0);
if ($nc) {
Log::info(sprintf('%s:- Setting zone to [%d]',self::LOGKEY,$nc->zone->zone_id));
$ftn['z'] = $nc->zone->zone_id;
}
}
// Create zone
Zone::unguard();
$zo = Zone::singleOrNew(['domain_id'=>$do->id,'zone_id'=>$ftn['z']]);
Zone::reguard();
if (! $zo->exists) {
$zo->active = TRUE;
$zo->notes = 'Auto created';
$zo->system_id = System::createUnknownSystem()->id;
$do->zones()->save($zo);
}
if (! $zo->active || ! $do->active) {
Log::alert(sprintf('%s:! Refusing to create address [%s] in disabled zone or domain',self::LOGKEY,$address));
return NULL;
}
// Create Address, assigned to $so
$o = new self;
$o->active = TRUE;
$o->zone_id = $zo->id;
$o->region_id = 0;
$o->host_id = $ftn['n'];
$o->node_id = $ftn['f'];
$o->point_id = $ftn['p'];
$o->role = $ftn['p'] ? self::NODE_POINT : self::NODE_UNKNOWN;
try {
$so->addresses()->save($o);
} catch (\Exception $e) {
Log::error(sprintf('%s:! ERROR creating address [%s]',self::LOGKEY,get_class($e)));
return NULL;
}
return $o;
}
/**
* Find a record in the DB for a node string, eg: 10:1/1.0
*
@ -382,45 +475,12 @@ class Address extends Model
* @return Address|null
* @throws \Exception
*/
public static function findFTN(string $address,bool $create=FALSE,System $so=NULL,bool $trashed=FALSE): ?self
public static function findFTN(string $address,bool $trashed=FALSE): ?self
{
$ftn = self::parseFTN($address);
$o = NULL;
// Are we looking for a region address
if (($ftn['f'] === 0) && $ftn['p'] === 0) {
$o = (new self)
->select('addresses.*')
->join('zones',['zones.id'=>'addresses.zone_id'])
->join('domains',['domains.id'=>'zones.domain_id'])
->when($trashed,function($query) {
$query->trashed();
},function($query) {
$query->active();
})
->where('zones.zone_id',$ftn['z'])
->where(function($q) use ($ftn) {
return $q
->where(function($q) use ($ftn) {
return $q->where('region_id',$ftn['n'])
->where('host_id',$ftn['n']);
});
})
->where('node_id',$ftn['f'])
->where('point_id',$ftn['p'])
->when($ftn['d'],function($query,$domain) {
$query->where('domains.name',$domain);
})
->when((! $ftn['d']),function($query) {
$query->where('zones.default',TRUE);
})
->single();
if ($o && $o->system->active)
return $o;
}
// Look for a normal address
$o = ($x=(new self)
$query = (new self)
->select('addresses.*')
->join('zones',['zones.id'=>'addresses.zone_id'])
->join('domains',['domains.id'=>'zones.domain_id'])
@ -430,32 +490,39 @@ class Address extends Model
$query->active();
})
->where('zones.zone_id',$ftn['z'])
->where(function($q) use ($ftn) {
return $q->where(function($qq) use ($ftn) {
return $qq
->where('region_id',$ftn['n'])
->where('host_id',$ftn['n']);
})
->orWhere(function($qq) use ($ftn) {
return $qq
->where('host_id',$ftn['n']);
});
})
->where('node_id',$ftn['f'])
->where('point_id',$ftn['p'])
->when($ftn['d'],function($query,$domain) {
$query->where('domains.name',$domain);
})
->when((! $ftn['d']),function($query) {
},function($query) {
$query->where('zones.default',TRUE);
}))
->single();
});
if ($o && $o->system->active)
return $o;
$q = $query->clone();
// Are we looking for a region address
if (($ftn['f'] === 0) && ($ftn['p'] === 0))
$o = $query
->where('region_id',$ftn['n'])
->where('host_id',$ftn['n'])
->single();
// Look for a normal address
if (! $o)
$o = $q
->where(function($q) use ($ftn) {
return $q
->where(function($q) use ($ftn) {
return $q
->where('region_id',$ftn['n'])
->where('host_id',$ftn['n']);
})
->orWhere('host_id',$ftn['n']);
})
->single();
// Check and see if we are a flattened domain, our address might be available with a different zone.
if ($ftn['p'] === 0) {
if (! $o && ($ftn['p'] === 0)) {
if ($ftn['d'])
$do = Domain::where(['name'=>$ftn['d']])->single();
else {
@ -463,81 +530,8 @@ class Address extends Model
$do = $zo?->domain;
}
if ($do && $do->flatten) {
if ($do && $do->flatten)
$o = self::findZone($do,$ftn['n'],$ftn['f'],$ftn['p'],$trashed);
if ($o && $o->system->active)
return $o;
}
}
if ($create) {
if (! $so) {
System::unguard();
$so = System::firstOrCreate([
'name' => 'Discovered System',
'sysop' => 'Unknown',
'location' => '',
'active' => TRUE,
]);
System::reguard();
}
if (! $ftn['d']) {
Log::alert(sprintf('%s:! Refusing to create address [%s] no domain available',self::LOGKEY,$address));
return NULL;
}
Log::debug(sprintf('%s:Creating AKA [%s] for [%s]',self::LOGKEY,$address,$so->name));
// Check Domain exists
Domain::unguard();
$do = Domain::singleOrNew(['name'=>$ftn['d']]);
Domain::reguard();
if (! $do->exists) {
$do->public = TRUE;
$do->active = TRUE;
$do->notes = 'Auto created';
$do->save();
}
// Create zone
Zone::unguard();
$zo = Zone::singleOrNew(['domain_id'=>$do->id,'zone_id'=>$ftn['z']]);
Zone::reguard();
if (! $zo->exists) {
$zo->active = TRUE;
$zo->notes = 'Auto created';
$zo->system_id = System::where('name','Discovered System')->first()->id;
$do->zones()->save($zo);
}
if (! $zo->active || ! $do->active) {
Log::alert(sprintf('%s:! Refusing to create address [%s] in disabled zone or domain',self::LOGKEY,$address));
return NULL;
}
// Create Address, assigned to $so
$o = new self;
$o->active = TRUE;
$o->zone_id = $zo->id;
$o->region_id = 0;
$o->host_id = $ftn['n'];
$o->node_id = $ftn['f'];
$o->point_id = $ftn['p'];
$o->role = $ftn['p'] ? self::NODE_POINT : self::NODE_UNKNOWN;
try {
$so->addresses()->save($o);
} catch (\Exception $e) {
Log::error(sprintf('%s:! ERROR creating address [%s] (%s)',self::LOGKEY,$x->toSql(),get_class($e)),['bindings'=>$x->getBindings()]);
return NULL;
}
}
return ($o && $o->system->active) ? $o : NULL;

View File

@ -13,10 +13,28 @@ class System extends Model
{
use HasFactory;
public const default = 'Discovered System';
protected $casts = [
'last_session' => 'datetime:Y-m-d H:i:s'
];
/* STATIC */
public static function createUnknownSystem(): self
{
self::unguard();
$so = self::firstOrCreate([
'name' => self::default,
'sysop' => 'Unknown',
'location' => '',
'active' => TRUE,
]);
self::reguard();
return $so;
}
/* SCOPES */
/**

View File

@ -43,15 +43,8 @@ class PacketTest extends TestCase
foreach ($pkt as $msg) {
$messages = TRUE;
$this->assertNotTrue($msg->isNetmail());
$this->assertNotFalse($msg->pathaddress->search($hub->id));
$this->assertCount(1,$msg->rogue_path);
$this->assertNotFalse($msg->rogue_path->search('21:999/1'));
$this->assertCount(3,$msg->rogue_seenby);
$this->assertNotFalse($msg->rogue_seenby->search('21:999/1'));
$this->assertNotFalse($msg->rogue_seenby->search('21:999/999'));
$this->assertCount(0,$msg->rogue_seenby);
}
$this->assertTrue($messages);
@ -79,8 +72,7 @@ class PacketTest extends TestCase
$messages = TRUE;
$this->assertNotTrue($msg->isNetmail());
$this->assertCount(1,$msg->rogue_path);
$this->assertNotFalse($msg->rogue_path->search('10:1/1'));
$this->assertNotFalse($msg->path->search('1/1 999/1'));
$this->assertCount(0,$msg->rogue_seenby);
}
@ -109,11 +101,8 @@ class PacketTest extends TestCase
foreach ($pkt as $msg) {
$messages = TRUE;
$this->assertNotTrue($msg->isNetmail());
$this->assertCount(0,$msg->rogue_path);
$this->assertCount(1,$msg->rogue_seenby);
$this->assertNotFalse($msg->rogue_seenby->search('10:1/1'));
$this->assertCount(0,$msg->rogue_seenby);
$this->assertNotFalse($msg->seenaddress->search($src->id));
}
@ -138,8 +127,7 @@ class PacketTest extends TestCase
$this->assertSame('21:1/151 6189F64C',$msg->msgid);
$this->assertSame('db727bd3778ddd457784ada4bf016010',md5($msg->message));
$this->assertSame('5b627ab5936b0550a97b738f4deff419',md5($msg->message_src));
$this->assertCount(3,$msg->rogue_path);
$this->assertCount(170,$msg->rogue_seenby);
$this->assertCount(0,$msg->rogue_seenby);
$this->assertContains('3/2744 4/100 106 5/100',$msg->seenby);
$this->assertContains('1/151 100 3/100',$msg->path);
$this->assertCount(11,$msg->seenby);
@ -164,8 +152,7 @@ class PacketTest extends TestCase
$this->assertSame('21:1/126 eec6e958',$msg->msgid);
$this->assertSame('5a525cc1c393292dc65160a852d4d615',md5($msg->message));
$this->assertSame('a3193edcc68521d4ed07da6db2aeb0b6',md5($msg->message_src));
$this->assertCount(3,$msg->rogue_path);
$this->assertCount(161,$msg->rogue_seenby);
$this->assertCount(0,$msg->rogue_seenby);
$this->assertContains('1/995 2/100 116 1202 3/100 105 107 108 109 110 111 112 113 117 119',$msg->seenby);
$this->assertContains('1/126 100 3/100',$msg->path);
$this->assertCount(10,$msg->seenby);
@ -191,7 +178,7 @@ class PacketTest extends TestCase
$this->assertSame('61078e680cda04c8b5eba0f712582e70',md5($msg->message));
$this->assertSame('b9d65d4f7319ded282f3f1986276ae79',md5($msg->message_src));
$this->assertCount(1,$msg->pathaddress);
$this->assertCount(1,$msg->rogue_seenby);
$this->assertCount(0,$msg->rogue_seenby);
$this->assertContains('1/1 999/1 999',$msg->seenby);
$this->assertContains('999/1',$msg->path);
$this->assertCount(1,$msg->seenby);
@ -204,6 +191,14 @@ class PacketTest extends TestCase
public function test_soh_in_origin()
{
$this->init();
Zone::unguard();
Address::unguard();
$zo = Zone::firstOrCreate(['zone_id'=>3,'default'=>TRUE,'active'=>TRUE,'domain_id'=>$this->do->id,'system_id'=>$this->so->id]);
$src = Address::firstOrCreate(['zone_id'=>$zo->id,'region_id'=>0,'host_id'=>712,'node_id'=>886,'point_id'=>0,'role'=>Address::NODE_ACTIVE,'active'=>TRUE,'system_id'=>$this->so->id]);
// This packet has a SOH<char>SOH sequence
$f = new File(__DIR__.'/data/test_msg_with_soh_in_origin.pkt');
@ -225,8 +220,7 @@ class PacketTest extends TestCase
$this->assertSame('3:712/886 220da89f',$msg->msgid);
$this->assertSame('9f5544bea46ef57a45f561b9e07dd71e',md5($msg->message));
$this->assertSame('9bf4b8c348ac235cc218577abf7140af',md5($msg->message_src));
$this->assertCount(3,$msg->rogue_path);
$this->assertCount(16,$msg->rogue_seenby);
$this->assertCount(0,$msg->rogue_seenby);
$this->assertContains('633/0 267 280 281 408 410 412 509 509 640/1384 712/114 550 620 848',$msg->seenby);
$this->assertContains('712/886 848 633/280',$msg->path);
$this->assertCount(2,$msg->seenby);
@ -237,8 +231,7 @@ class PacketTest extends TestCase
$this->assertSame('',$msg->msgid);
$this->assertSame('b975057002def556c5a9497aacd000fb',md5($msg->message));
$this->assertSame('c90dd234d2aa029af22c453a25b79a4e',md5($msg->message_src));
$this->assertCount(3,$msg->rogue_path);
$this->assertCount(19,$msg->rogue_seenby);
$this->assertCount(0,$msg->rogue_seenby);
$this->assertContains('633/267 280 281 384 408 410 412 418 420 509 509 712/848 770/1 100 330',$msg->seenby);
$this->assertContains('772/210 770/1 633/280',$msg->path);
$this->assertCount(2,$msg->seenby);