#!/usr/bin/env perl
use strict;
use warnings;
use Test::More;
use FixMyStreet::App;
use FindBin;
use lib "$FindBin::Bin/../perllib";
use lib "$FindBin::Bin/../commonlib/perllib";
use_ok( 'Open311::PopulateServiceList' );
use_ok( 'Open311' );
my $processor = Open311::PopulateServiceList->new();
ok $processor, 'created object';
my $body = FixMyStreet::App->model('DB::Body')->find_or_create( {
id => 1,
name => 'Body Numero Uno',
} );
$body->body_areas->find_or_create({
area_id => 1
} );
my $BROMLEY = 'Bromley Council';
my $bromley = FixMyStreet::App->model('DB::Body')->find_or_create( {
id => 2482,
name => $BROMLEY,
} );
$bromley->update({ name => $BROMLEY });
$bromley->body_areas->find_or_create({
area_id => 2482
} );
subtest 'check basic functionality' => sub {
FixMyStreet::App->model('DB::Contact')->search( { body_id => 1 } )->delete();
my $service_list = get_xml_simple_object( get_standard_xml() );
my $processor = Open311::PopulateServiceList->new();
$processor->_current_body( $body );
$processor->process_services( $service_list );
my $contact_count = FixMyStreet::App->model('DB::Contact')->search( { body_id => 1 } )->count();
is $contact_count, 3, 'correct number of contacts';
};
subtest 'check non open311 contacts marked as deleted' => sub {
FixMyStreet::App->model('DB::Contact')->search( { body_id => 1 } )->delete();
my $contact = FixMyStreet::App->model('DB::Contact')->create(
{
body_id => 1,
email => 'contact@example.com',
category => 'An old category',
confirmed => 1,
deleted => 0,
editor => $0,
whenedited => \'ms_current_timestamp()',
note => 'test contact',
}
);
my $service_list = get_xml_simple_object( get_standard_xml() );
my $processor = Open311::PopulateServiceList->new();
$processor->_current_body( $body );
$processor->process_services( $service_list );
my $contact_count = FixMyStreet::App->model('DB::Contact')->search( { body_id => 1 } )->count();
is $contact_count, 4, 'correct number of contacts';
$contact_count = FixMyStreet::App->model('DB::Contact')->search( { body_id => 1, deleted => 1 } )->count();
is $contact_count, 1, 'correct number of deleted contacts';
};
subtest 'check email changed if matching category' => sub {
FixMyStreet::App->model('DB::Contact')->search( { body_id => 1 } )->delete();
my $contact = FixMyStreet::App->model('DB::Contact')->create(
{
body_id => 1,
email => '009',
category => 'Cans left out 24x7',
confirmed => 1,
deleted => 0,
editor => $0,
whenedited => \'ms_current_timestamp()',
note => 'test contact',
}
);
ok $contact, 'contact created';
my $service_list = get_xml_simple_object( get_standard_xml() );
my $processor = Open311::PopulateServiceList->new();
$processor->_current_body( $body );
$processor->process_services( $service_list );
$contact->discard_changes;
is $contact->email, '001', 'email unchanged';
is $contact->confirmed, 1, 'contact still confirmed';
is $contact->deleted, 0, 'contact still not deleted';
my $contact_count = FixMyStreet::App->model('DB::Contact')->search( { body_id => 1 } )->count();
is $contact_count, 3, 'correct number of contacts';
};
subtest 'check category name changed if updated' => sub {
FixMyStreet::App->model('DB::Contact')->search( { body_id => 1 } )->delete();
my $contact = FixMyStreet::App->model('DB::Contact')->create(
{
body_id => 1,
email => '001',
category => 'Bins left out 24x7',
confirmed => 1,
deleted => 0,
editor => $0,
whenedited => \'ms_current_timestamp()',
note => 'test contact',
}
);
ok $contact, 'contact created';
my $service_list = get_xml_simple_object( get_standard_xml() );
my $processor = Open311::PopulateServiceList->new();
$processor->_current_body( $body );
$processor->process_services( $service_list );
$contact->discard_changes;
is $contact->email, '001', 'email unchanged';
is $contact->category, 'Cans left out 24x7', 'category changed';
is $contact->confirmed, 1, 'contact still confirmed';
is $contact->deleted, 0, 'contact still not deleted';
my $contact_count = FixMyStreet::App->model('DB::Contact')->search( { body_id => 1 } )->count();
is $contact_count, 3, 'correct number of contacts';
};
subtest 'check conflicting contacts not changed' => sub {
FixMyStreet::App->model('DB::Contact')->search( { body_id => 1 } )->delete();
my $contact = FixMyStreet::App->model('DB::Contact')->create(
{
body_id => 1,
email => 'existing@example.com',
category => 'Cans left out 24x7',
confirmed => 1,
deleted => 0,
editor => $0,
whenedited => \'ms_current_timestamp()',
note => 'test contact',
}
);
ok $contact, 'contact created';
my $contact2 = FixMyStreet::App->model('DB::Contact')->create(
{
body_id => 1,
email => '001',
category => 'Bins left out 24x7',
confirmed => 1,
deleted => 0,
editor => $0,
whenedited => \'ms_current_timestamp()',
note => 'test contact',
}
);
ok $contact2, 'contact created';
my $service_list = get_xml_simple_object( get_standard_xml() );
my $processor = Open311::PopulateServiceList->new();
$processor->_current_body( $body );
$processor->process_services( $service_list );
$contact->discard_changes;
is $contact->email, 'existing@example.com', 'first contact email unchanged';
is $contact->category, 'Cans left out 24x7', 'first contact category unchanged';
is $contact->confirmed, 1, 'first contact contact still confirmed';
is $contact->deleted, 0, 'first contact contact still not deleted';
$contact2->discard_changes;
is $contact2->email, '001', 'second contact email unchanged';
is $contact2->category, 'Bins left out 24x7', 'second contact category unchanged';
is $contact2->confirmed, 1, 'second contact contact still confirmed';
is $contact2->deleted, 0, 'second contact contact still not deleted';
my $contact_count = FixMyStreet::App->model('DB::Contact')->search( { body_id => 1 } )->count();
is $contact_count, 4, 'correct number of contacts';
};
subtest 'check meta data population' => sub {
my $processor = Open311::PopulateServiceList->new();
my $meta_xml = '
100
true
type
string
true
Type of bin
1
Type of bin
';
my $contact = FixMyStreet::App->model('DB::Contact')->find_or_create(
{
body_id => 1,
email => '001',
category => 'Bins left out 24x7',
confirmed => 1,
deleted => 0,
editor => $0,
whenedited => \'ms_current_timestamp()',
note => 'test contact',
}
);
my $o = Open311->new(
jurisdiction => 'mysociety',
endpoint => 'http://example.com',
test_mode => 1,
test_get_returns => { 'services/100.xml' => $meta_xml }
);
$processor->_current_open311( $o );
$processor->_current_body( $bromley );
$processor->_current_service( { service_code => 100 } );
$processor->_add_meta_to_contact( $contact );
my $extra = [ {
variable => 'true',
code => 'type',
datatype => 'string',
required => 'true',
datatype_description => 'Type of bin',
order => 1,
description => 'Type of bin'
} ];
$contact->discard_changes;
is_deeply $contact->extra, $extra, 'meta data saved';
};
for my $test (
{
desc => 'check meta data added to existing contact',
has_meta => 1,
orig_meta => undef,
end_meta => [ {
variable => 'true',
code => 'type',
datatype => 'string',
required => 'true',
datatype_description => 'Type of bin',
order => 1,
description => 'Type of bin'
} ],
meta_xml => '
100
true
type
string
true
Type of bin
1
Type of bin
',
},
{
desc => 'check meta data updated',
has_meta => 1,
orig_meta => [ {
variable => 'true',
code => 'type',
datatype => 'string',
required => 'true',
datatype_description => 'Type of bin',
order => 1,
description => 'Type of bin'
} ],
end_meta => [ {
variable => 'true',
code => 'type',
datatype => 'string',
required => 'true',
datatype_description => 'Colour of bin',
order => 1,
description => 'Colour of bin'
} ],
meta_xml => '
100
true
type
string
true
Colour of bin
1
Colour of bin
',
},
{
desc => 'check meta data removed',
has_meta => 0,
end_meta => undef,
orig_meta => [ {
variable => 'true',
code => 'type',
datatype => 'string',
required => 'true',
datatype_description => 'Type of bin',
order => 1,
description => 'Type of bin'
} ],
meta_xml => '
100
true
type
string
true
Type of bin
1
Type of bin
',
},
{
desc => 'check empty meta data handled',
has_meta => 1,
orig_meta => undef,
end_meta => undef,
meta_xml => '
100
',
},
) {
subtest $test->{desc} => sub {
my $processor = Open311::PopulateServiceList->new();
my $services_xml = '
100
Cans left out 24x7
Garbage or recycling cans that have been left out for more than 24 hours after collection. Violators will be cited.
false
realtime
lorem, ipsum, dolor
sanitation
';
if ( $test->{has_meta} ) {
$services_xml =~ s/metadata>false/metadata>true/ms;
}
my $contact = FixMyStreet::App->model('DB::Contact')->find_or_create(
{
body_id => 1,
email => '100',
category => 'Cans left out 24x7',
confirmed => 1,
deleted => 0,
editor => $0,
whenedited => \'ms_current_timestamp()',
note => 'test contact',
}
);
$contact->update( { extra => $test->{orig_meta} } );
my $o = Open311->new(
jurisdiction => 'mysociety',
endpoint => 'http://example.com',
test_mode => 1,
test_get_returns => { 'services.xml' => $services_xml, 'services/100.xml' => $test->{meta_xml} }
);
my $service_list = get_xml_simple_object( $services_xml );
$service_list = { service => [ $service_list->{ service } ] };
$processor->_current_open311( $o );
$processor->_current_body( $body );
$processor->process_services( $service_list );
$contact->discard_changes;
is_deeply $contact->extra, $test->{end_meta}, 'meta data saved';
};
}
subtest 'check attribute ordering' => sub {
my $processor = Open311::PopulateServiceList->new();
my $meta_xml = '
100
true
type
string
true
Type of bin
1
Type of bin
true
colour
string
true
Colour of bin
3
Colour of bin
true
size
string
true
Size of bin
2
Size of bin
';
my $contact = FixMyStreet::App->model('DB::Contact')->find_or_create(
{
body_id => 1,
email => '001',
category => 'Bins left out 24x7',
confirmed => 1,
deleted => 0,
editor => $0,
whenedited => \'ms_current_timestamp()',
note => 'test contact',
}
);
my $o = Open311->new(
jurisdiction => 'mysociety',
endpoint => 'http://example.com',
test_mode => 1,
test_get_returns => { 'services/100.xml' => $meta_xml }
);
$processor->_current_open311( $o );
$processor->_current_body( $body );
$processor->_current_service( { service_code => 100 } );
$processor->_add_meta_to_contact( $contact );
my $extra = [
{
variable => 'true',
code => 'type',
datatype => 'string',
required => 'true',
datatype_description => 'Type of bin',
order => 1,
description => 'Type of bin'
},
{
variable => 'true',
code => 'size',
datatype => 'string',
required => 'true',
datatype_description => 'Size of bin',
order => 2,
description => 'Size of bin'
},
{
variable => 'true',
code => 'colour',
datatype => 'string',
required => 'true',
datatype_description => 'Colour of bin',
order => 3,
description => 'Colour of bin'
},
];
$contact->discard_changes;
is_deeply $contact->extra, $extra, 'meta data re-ordered correctly';
};
subtest 'check bromely skip code' => sub {
my $processor = Open311::PopulateServiceList->new();
my $meta_xml = '
100
true
type
string
true
Type of bin
1
Type of bin
true
title
string
true
Type of bin
1
Type of bin
true
report_url
string
true
Type of bin
1
Type of bin
';
my $contact = FixMyStreet::App->model('DB::Contact')->find_or_create(
{
body_id => 1,
email => '001',
category => 'Bins left out 24x7',
confirmed => 1,
deleted => 0,
editor => $0,
whenedited => \'ms_current_timestamp()',
note => 'test contact',
}
);
my $o = Open311->new(
jurisdiction => 'mysociety',
endpoint => 'http://example.com',
test_mode => 1,
test_get_returns => { 'services/100.xml' => $meta_xml }
);
$processor->_current_open311( $o );
$processor->_current_body( $bromley );
$processor->_current_service( { service_code => 100 } );
$processor->_add_meta_to_contact( $contact );
my $extra = [ {
variable => 'true',
code => 'type',
datatype => 'string',
required => 'true',
datatype_description => 'Type of bin',
order => 1,
description => 'Type of bin'
} ];
$contact->discard_changes;
is_deeply $contact->extra, $extra, 'only non std bromley meta data saved';
$processor->_current_body( $body );
$processor->_add_meta_to_contact( $contact );
$extra = [
{
variable => 'true',
code => 'type',
datatype => 'string',
required => 'true',
datatype_description => 'Type of bin',
order => 1,
description => 'Type of bin'
},
{
variable => 'true',
code => 'title',
datatype => 'string',
required => 'true',
datatype_description => 'Type of bin',
order => 1,
description => 'Type of bin'
},
{
variable => 'true',
code => 'report_url',
datatype => 'string',
required => 'true',
datatype_description => 'Type of bin',
order => 1,
description => 'Type of bin'
},
];
$contact->discard_changes;
is_deeply $contact->extra, $extra, 'all meta data saved for non bromley';
};
sub get_standard_xml {
return qq{
001
Cans left out 24x7
Garbage or recycling cans that have been left out for more than 24 hours after collection. Violators will be cited.
false
realtime
lorem, ipsum, dolor
sanitation
002
false
realtime
lorem, ipsum, dolor
street
Construction plate shifted
Metal construction plate covering the street or sidewalk has been moved.
003
false
realtime
lorem, ipsum, dolor
street
Curb or curb ramp defect
Sidewalk curb or ramp has problems such as cracking, missing pieces, holes, and/or chipped curb.
};
}
sub get_xml_simple_object {
my $xml = shift;
my $simple = XML::Simple->new();
my $obj;
eval {
$obj = $simple->XMLin( $xml );
};
die $@ if $@;
return $obj;
}
done_testing();