use 5.10.1; use strict; use warnings; use lib qw(. lib t); # Each call to run_rpc adds 3 tests use Test::More tests => 99; use Capture::Tiny ':all'; use HTTP::Parser; use JSON; use Bugzilla; use Bugzilla::CGI; use Bugzilla::Constants; use Bugzilla::Error; use Bugzilla::WebService::Constants; use Bugzilla::WebService::Server::JSONRPC; BEGIN { $ENV{PROJECT} = 'tests'; $ENV{REQUEST_METHOD} = 'POST'; $ENV{CONTENT_TYPE} = 'application/json'; $ENV{PERL_JSON_DEBUG} = 1; } Bugzilla->usage_mode(USAGE_MODE_JSON); my $dbh = Bugzilla->dbh(); my $rpc_debug = 0; my $cgi = Bugzilla->cgi; $cgi->header('application/json'); my %args; local @INC = (bz_locations()->{extensionsdir}, @INC); my $token = undef; # Login to get a token my %login_args = (login => 'myadmin@example.net', password => 'DudeMcDude',); my $res = run_rpc('User.login', \%login_args); $token = $res->{result}->{token}; my $user_id = $res->{result}->{id}; # Product %args = ( name => 'Bugzilla', description => 'This is a product to test the webservices', version => '5.0', defaultmilestone => '5.0', is_open => '1', ); $res = run_rpc('Product.create', \%args); my $prod_id = $res->{result}->{id}; # hmm this is required to make product editable ... if (not defined $res->{error}) { my $sql = "INSERT INTO group_control_map VALUES(1,$prod_id,0,1,0,0,1,0,0)"; Bugzilla->dbh->do($sql); } %args = (names => ['Bugzilla'],); $res = run_rpc('Product.get', \%args); %args = ( names => ['Bugzilla'], description => 'This is a product to test the JSONRPC webservice', ); $res = run_rpc('Product.update', \%args); # Component %args = ( component => 'Bugzilla General', description => 'This is a Component to test the webservices', product => 'Bugzilla', isopen => '1', default_assignee => 'myadmin@example.net', default_qa_contact => 'myadmin@example.net', ); $res = run_rpc('Component.create', \%args); %args = (names => [{component => 'Bugzilla General', product => 'Bugzilla'}],); $res = run_rpc('Component.get', \%args); %args = ( component => 'Security', description => 'This is a Security Component ', product => 'Bugzilla', isopen => '1', default_assignee => 'myadmin@example.net', default_qa_contact => 'myadmin@example.net', ); $res = run_rpc('Component.create', \%args); %args = ( names => [{component => 'Bugzilla General', product => 'Bugzilla'}], updates => {description => 'This is a Component to test the JSONRPC webservice'}, ); $res = run_rpc('Component.update', \%args); # Have to clear out cache to make product visible $res = run_rpc('User.logout', {}); $res = run_rpc('User.login', \%login_args); $token = $res->{result}->{token}; my $user = Bugzilla::User->new($user_id); $user->clear_product_cache(); # Bug %args = ( summary => 'Test Bug', description => 'This is a Bug to test the webservices 中英字典', component => 'Bugzilla General', product => 'Bugzilla', version => '5.0', severity => 'normal', op_sys => 'linux', priority => 'normal', rep_platform => 'all', ); $res = run_rpc('Bug.create', \%args); my $bug_id = $res->{result}->{id}; %args = (ids => [$bug_id]); $res = run_rpc('Bug.get', \%args); %args = (ids => [$bug_id], status => 'ASSIGNED',); $res = run_rpc('Bug.update', \%args); # Bug 2005292 - 'comments.id' should return only ID %args = (ids => [$bug_id], include_fields => ['id', 'comments.id']); $res = run_rpc('Bug.search', \%args); ok( exists $res->{'result'}->{'bugs'} && exists $res->{'result'}->{'bugs'}->[0]->{'comments'} && exists $res->{'result'}->{'bugs'}->[0]->{'comments'}->[0]->{'id'} && scalar keys(%{$res->{'result'}->{'bugs'}->[0]->{'comments'}->[0]}) == 1, 'Comments have 1 key and it is "id"' ) || diag(explain $res); # Bug 2005292 - 'comments' should return more that ID %args = (ids => [$bug_id], include_fields => ['id', 'comments']); $res = run_rpc('Bug.search', \%args); ok( exists $res->{'result'}->{'bugs'} && exists $res->{'result'}->{'bugs'}->[0]->{'comments'} && exists $res->{'result'}->{'bugs'}->[0]->{'comments'}->[0]->{'id'} && scalar keys(%{$res->{'result'}->{'bugs'}->[0]->{'comments'}->[0]}) > 1, 'Comments have more than 1 key' ) || diag(explain $res); #flagtype %args = ( name => 'TheFlag', description => 'This Flag is for testing FlagTypes', vis_group => 'editbugs', category => 'release', ); $res = run_rpc('FlagType.create', \%args); my $flagid = $res->{result}->{id}; %args = (ids => [$flagid], grant_group => 'admin', inclusions => ['Bugzilla'],); $res = run_rpc('FlagType.update', \%args); # agile team %args = (name => 'Bugzilla', product => 'Bugzilla',); $res = run_rpc('Agile.Team.create', \%args); %args = (team => 'Bugzilla',); $res = run_rpc('Agile.Team.get', \%args); my $team_id = $res->{result}->{id}; # set default pool on a component %args = ( names => [{component => 'Bugzilla General', product => 'Bugzilla'}], updates => {default_pool => 2}, ); $res = run_rpc('Component.update', \%args); %args = ( subcomponent => 'Less General', component => 'Bugzilla General', product => 'Bugzilla', description => 'testing sub components', default_assignee => 'myadmin@example.net', ); $res = run_rpc('SubComponent.create', \%args); %args = ( names => [{ subcomponent => 'Less General', component => 'Bugzilla General', product => 'Bugzilla', }], updates => {default_pool => 2}, ); $res = run_rpc('SubComponent.update', \%args); #diag explain $res; # set agile_team on a product/component/subcomponent %args = (names => ['Bugzilla'], agile_team => $team_id,); $res = run_rpc('Product.update', \%args); %args = ( names => [{component => 'Bugzilla General', product => 'Bugzilla'}], updates => {agile_team => $team_id}, ); $res = run_rpc('Component.update', \%args); %args = ( names => [{ subcomponent => 'Less General', component => 'Bugzilla General', product => 'Bugzilla', }], updates => {agile_team => $team_id}, ); $res = run_rpc('SubComponent.update', \%args); %args = ( who => $login_args{login}, from => '2018-01-01', to => '2200-01-01', sort => 'bugs', ); $res = run_rpc('ActivityReport.user_activity', \%args); %args = (product => 'Bugzilla', ids_only => 1); $res = run_rpc('Bug.search', \%args); ok( exists $res->{'result'}->{'bugs'} && exists $res->{'result'}->{'bugs'} && exists $res->{'result'}->{'bugs'}->[0]->{'id'} && scalar keys(%{$res->{'result'}->{'bugs'}->[0]}) == 1, 'ids_only: bugs have 1 key and it is "id"' ) || diag(explain $res); # Ensure LIMIT removal doesn't break SQL %args = (ids_only => 1, alias => 'LIMIT', cf_release_notes => q{' ) GROUP BY bugs.bug_id, bugs.bug_severity,bugs.priority,bugs.bug_status,bugs.resolution,map_product.name,map_component.name,bugs.short_desc,map_priority.sortkey,map_priority.value,map_bug_severity.sortkey,map_bug_severity.value LIMIT 1; update fake_table set fake_field = 1 where fake_field <> 1; SELECT bugs.bug_id AS bug_id, bugs.bug_severity AS bug_severity, bugs.priority AS priority, bugs.bug_status AS bug_status, bugs.resolution AS resolution, map_product.name AS product, map_component.name AS component, bugs.short_desc AS short_desc FROM bugs LEFT JOIN bug_group_map AS security_map ON bugs.bug_id = security_map.bug_id LEFT JOIN cc AS security_cc ON bugs.bug_id = security_cc.bug_id AND security_cc.who = 1 INNER JOIN products AS map_product ON bugs.product_id = map_product.id INNER JOIN components AS map_component ON bugs.component_id = map_component.id INNER JOIN priority AS map_priority ON bugs.priority = map_priority.value INNER JOIN bug_severity AS map_bug_severity ON bugs.bug_severity = map_bug_severity.value WHERE bugs.bug_id = 1 -- - }); $res = run_rpc('Bug.search', \%args); $res = run_rpc('Agile.Team.get_visible', \%args); ok( exists $res->{'result'}->{'teams'} && exists $res->{'result'}->{'teams'}->[0]->{'id'} && scalar @{$res->{'result'}->{'teams'}} == 1, 'get_visible: there is 1 team' ) || diag(explain $res); $res = run_rpc('Agile.Team.get_editable', \%args); ok( exists $res->{'result'}->{'teams'} && exists $res->{'result'}->{'teams'}->[0]->{'id'} && scalar @{$res->{'result'}->{'teams'}} == 1, 'get_editable: there is 1 team' ) || diag(explain $res); $res = run_rpc('User.whoami', \%args); ok( exists $res->{'result'}->{'name'} && $res->{'result'}->{'name'} eq 'myadmin@example.net', 'whoami: login is correct' ) || diag(explain $res); exit; # Run a jsonrpc request sub run_rpc { my ($method, $params) = @_; ## We need to reset this as the cache survives calls Bugzilla->request_cache->{filter_wants} = {}; my %args = ( method => $method, version => "1.1", token => $token, params => ($params || {}), ); if ($rpc_debug) { diag explain \%args; } $cgi->delete_all(); $cgi->cgi_error(""); $cgi->param('POSTDATA', to_json(\%args)); my $server = new Bugzilla::WebService::Server::JSONRPC; my ($stdout, $stderr, @result) = capture { $server->dispatch(WS_DISPATCH)->handle() }; ok($result[0], $method); ## Useful for debugging if ($rpc_debug) { diag("stdout"); diag explain $stdout; diag("stderr"); diag explain $stderr; diag("result"); diag explain \@result; } my $parser = HTTP::Parser->new(response => 1); ok($parser->add("HTTP/1.1\n" . $stdout), 'Parse response'); my $resp = from_json($parser->object()->decoded_content()); ok(!exists($resp->{error}), "no errors for $method") || diag explain $resp; eval { $dbh->bz_rollback_transaction() if ($dbh->bz_in_transaction); }; return ($resp); }