The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
#!/usr/bin/env perl

use strict;
use warnings;

use Test::Most;
use File::Temp;
use File::Spec;
use JSON;
use HTTP::Response;
use Test::MockModule;

BEGIN {
    use_ok('JIRA::Client::Automated');
}

sub dispatch {
    my %dispatch = @_;

    return sub {
        my ($self, $request) = @_;

        my $path = $request->uri->path;
        $path =~ s!^/rest/api/latest/!!;

        my $sub = $dispatch{$path} or die "no sub to dispatch to for [$path]";
        $sub->($request);
    };
}

my $JCA = 'JIRA::Client::Automated';

my $json = JSON->new->utf8()->allow_nonref;

my $jira = JIRA::Client::Automated->new('http://my.jira.server', 'username', 'password');

# Create new JCA object
ok $jira, 'new object';
isa_ok($jira, $JCA);

subtest 'create' => sub {
    subtest 'basic creation' => sub {
        my $request;
        my $ua = Test::MockModule->new('LWP::UserAgent');
        $ua->mock(request => dispatch(
            'issue/createmeta' => sub {
                return HTTP::Response->new('200', 'OK', [], $json->encode(createmeta()));
            },
            'issue/' => sub {
                my ($request_) = @_;

                $request = $request_;
                my $body = {
                    key => 'MyProject-123'
                };
                return HTTP::Response->new('200', 'OK', [], $json->encode($body));
            },
        ));

        # Create an issue
        my $issue = $jira->create_issue(
            'MyProject', 'Bug',
            "$JCA Test Script",
            "Created by $JCA Test Script automatically.",
            {
                labels => ["Commentary"] });

        ok($issue, 'create_issue');
        isa_ok($issue, 'HASH');
        is $issue->{key}, 'MyProject-123', 'hash returned contains key';

        my $request_content = $json->decode($request->decoded_content);
        cmp_deeply(
            $request_content,
            {
                'fields' => {
                    'description' => 'Created by JIRA::Client::Automated Test Script automatically.',
                    'issuetype' => {
                        'name' => 'Bug'
                    },
                    'labels' => [
                        'Commentary'
                    ],
                    'project' => {
                        'key' => 'MyProject'
                    },
                    'summary' => 'JIRA::Client::Automated Test Script'
                }
            },
            'request ok') or explain $request_content;
    };

    subtest 'creation with custom fields' => sub {
        subtest 'custom field isa single-select' => sub {
            my $request;
            my $ua = Test::MockModule->new('LWP::UserAgent');
            $ua->mock(request => dispatch(
                'issue/createmeta' => sub {
                    return HTTP::Response->new('200', 'OK', [], $json->encode(createmeta()));
                },
                'issue/' => sub {
                    my ($request_) = @_;

                    $request = $request_;
                    my $body = {
                        key => 'MyProject-123'
                    };
                    return HTTP::Response->new('200', 'OK', [], $json->encode($body));
                },
            ));

            # Create an issue
            my $issue = $jira->create_issue(
                'MyProject', 'Task',
                "$JCA Test Script",
                "Created by $JCA Test Script automatically.",
                {
                    Group => 'Management',
                }
            );

            ok($issue, 'create_issue');
            isa_ok($issue, 'HASH');
            is $issue->{key}, 'MyProject-123', 'hash returned contains key';

            my $request_content = $json->decode($request->decoded_content);
            cmp_deeply(
                $request_content,
                {
                    'fields' => {
                        'description' => 'Created by JIRA::Client::Automated Test Script automatically.',
                        'issuetype' => {
                            'name' => 'Task'
                        },
                        'project' => {
                            'key' => 'MyProject'
                        },
                        'summary' => 'JIRA::Client::Automated Test Script',
                        customfield_11883 => {
                            id => 13602,
                        },
                    }
                },
                'request ok') or explain $request_content;
        };

        subtest 'custom field isa multi-select' => sub {
            my $request;
            my $ua = Test::MockModule->new('LWP::UserAgent');
            $ua->mock(request => dispatch(
                'issue/createmeta' => sub {
                    return HTTP::Response->new('200', 'OK', [], $json->encode(createmeta()));
                },
                'issue/' => sub {
                    my ($request_) = @_;

                    $request = $request_;
                    my $body = {
                        key => 'MyProject-123'
                    };
                    return HTTP::Response->new('200', 'OK', [], $json->encode($body));
                },
            ));

            # Create an issue
            my $issue = $jira->create_issue(
                'MyProject', 'Task',
                "$JCA Test Script",
                "Created by $JCA Test Script automatically.",
                {
                    Group => [
                        'Management',
                        'DevOps',
                    ],
                }
            );

            ok($issue, 'create_issue');
            isa_ok($issue, 'HASH');
            is $issue->{key}, 'MyProject-123', 'hash returned contains key';

            my $request_content = $json->decode($request->decoded_content);
            cmp_deeply(
                $request_content,
                {
                    'fields' => {
                        'description' => 'Created by JIRA::Client::Automated Test Script automatically.',
                        'issuetype' => {
                            'name' => 'Task'
                        },
                        'project' => {
                            'key' => 'MyProject'
                        },
                        'summary' => 'JIRA::Client::Automated Test Script',
                        customfield_11883 => [
                            { id => 13602 },
                            { id => 13107 },
                        ],
                    }
                },
                'request ok') or explain $request_content;
        };
    };
};

subtest 'get_issue' => sub {
    my $request;
    my $ua = Test::MockModule->new('LWP::UserAgent');
    $ua->mock(request => dispatch(
        'issue/createmeta' => sub {
            return HTTP::Response->new('200', 'OK', [], $json->encode(createmeta()));
        },
        'issue/MyProject-123' => sub {
            my $body = _get_issue();
            return HTTP::Response->new('200', 'OK', [], $json->encode($body));
        },
    ));

    # Create an issue
    my $issue = $jira->get_issue('MyProject-123');

    isa_ok($issue, 'HASH');
    is $issue->{key}, 'MyProject-123', 'hash returned contains key';

    cmp_deeply(
        $issue,
        {
            expand => 'renderedFields,names,schema,transitions,operations,editmeta,changelog',
            key => 'MyProject-123',
            id => 499114,
            self => 'https://my.jira.server/rest/api/latest/issue/499114',
            fields => {
                description => 'Created by JIRA::Client::Automated Test Script automatically.',
                issuetype => {
                    description => "A task that needs to be done.",
                    iconUrl => "https://my.jira.server/images/icons/issuetypes/task.png",
                    id => 3,
                    name => "Task",
                    self => "https://my.jira.server/rest/api/2/issuetype/3",
                    subtask => bless(do{\(my $o = 0)}, "JSON::XS::Boolean"),
                },
                project => {
                    id => 12881,
                    key => 'MyProject',
                    name => 'My Project',
                    self => 'https://my.jira.server/rest/api/2/project/12881',
                },
                summary => 'JIRA::Client::Automated Test Script',
                'NBX Tiers' => [ 'WS', 'MW', 'AG' ],
                COS => 'Standard',
                Group => 'DevOps',
                Reviewers => undef,
                status => {
                    description => "This issue is being actively worked on at the moment by the assignee.",
                    iconUrl => "https://my.jira.server/images/icons/statuses/inprogress.png",
                    id => 3,
                    name => "In Development",
                    self => "https://my.jira.server/rest/api/2/status/3",
                    statusCategory => {
                        colorName => "yellow",
                        id => 4,
                        key => "indeterminate",
                        name => "In Progress",
                        self => "https://my.jira.server/rest/api/2/statuscategory/4",
                    },
                },
            }
        },
        'request ok') or explain $issue;
};

done_testing();

sub createmeta {
    my $a = {
        expand   => "projects",
        projects => [
            {
                expand => "issuetypes",
                id => 11083,
                issuetypes => [
                    {
                        description => "A task that needs to be done.",
                        expand      => "fields",
                        fields      => {
                            assignee => {
                                hasDefaultValue => bless(do{\(my $o = 0)}, "JSON::XS::Boolean"),
                                name => "Assignee",
                                operations => ["set"],
                                required => 'fix',
                                schema => { system => "assignee", type => "user" },
                            },
                            customfield_11882 => {
                                allowedValues => [
                                    {
                                        id => 13094,
                                        self => "https://my.jira.server/rest/api/2/customFieldOption/13094",
                                        value => "Expedite",
                                    },
                                    {
                                        id => 13862,
                                        self => "https://my.jira.server/rest/api/2/customFieldOption/13862",
                                        value => "Defect",
                                    },
                                    {
                                        id => 13095,
                                        self => "https://my.jira.server/rest/api/2/customFieldOption/13095",
                                        value => "Standard",
                                    },
                                    {
                                        id => 13096,
                                        self => "https://my.jira.server/rest/api/2/customFieldOption/13096",
                                        value => "Fixed Date",
                                    },
                                    {
                                        id => 13097,
                                        self => "https://my.jira.server/rest/api/2/customFieldOption/13097",
                                        value => "Intangeable",
                                    },
                                ],
                                hasDefaultValue => bless(do{\(my $o = 1)}, "JSON::XS::Boolean"),
                                name => "COS",
                                operations => ["set"],
                                required => 'fix',
                                schema => {
                                    custom => "com.atlassian.jira.plugin.system.customfieldtypes:select",
                                    customId => 11882,
                                    type => "string",
                                },
                            },
                            customfield_11883 => {
                                allowedValues => [
                                    {
                                        id => 13098,
                                        self => "https://my.jira.server/rest/api/2/customFieldOption/13098",
                                        value => "Network",
                                    },
                                    {
                                        id => 13099,
                                        self => "https://my.jira.server/rest/api/2/customFieldOption/13099",
                                        value => "Windows",
                                    },
                                    {
                                        id => 13101,
                                        self => "https://my.jira.server/rest/api/2/customFieldOption/13101",
                                        value => "Linux / Unix",
                                    },
                                    {
                                        id => 13100,
                                        self => "https://my.jira.server/rest/api/2/customFieldOption/13100",
                                        value => "Storage",
                                    },
                                    {
                                        id => 13107,
                                        self => "https://my.jira.server/rest/api/2/customFieldOption/13107",
                                        value => "DevOps",
                                    },
                                    {
                                        id => 13108,
                                        self => "https://my.jira.server/rest/api/2/customFieldOption/13108",
                                        value => "DBA",
                                    },
                                    {
                                        id => 13492,
                                        self => "https://my.jira.server/rest/api/2/customFieldOption/13492",
                                        value => "DC",
                                    },
                                    {
                                        id => 13493,
                                        self => "https://my.jira.server/rest/api/2/customFieldOption/13493",
                                        value => "VMWare",
                                    },
                                    {
                                        id => 13494,
                                        self => "https://my.jira.server/rest/api/2/customFieldOption/13494",
                                        value => "Monitoring",
                                    },
                                    {
                                        id => 13495,
                                        self => "https://my.jira.server/rest/api/2/customFieldOption/13495",
                                        value => "Backup",
                                    },
                                    {
                                        id => 13600,
                                        self => "https://my.jira.server/rest/api/2/customFieldOption/13600",
                                        value => "Architect",
                                    },
                                    {
                                        id => 13601,
                                        self => "https://my.jira.server/rest/api/2/customFieldOption/13601",
                                        value => "Infosec",
                                    },
                                    {
                                        id => 13602,
                                        self => "https://my.jira.server/rest/api/2/customFieldOption/13602",
                                        value => "Management",
                                    },
                                    {
                                        id => 13603,
                                        self => "https://my.jira.server/rest/api/2/customFieldOption/13603",
                                        value => "Jira Admin",
                                    },
                                    {
                                        id => 13861,
                                        self => "https://my.jira.server/rest/api/2/customFieldOption/13861",
                                        value => "VOIP",
                                    },
                                ],
                                hasDefaultValue => 'fix',
                                name => "Group",
                                operations => ["set"],
                                required => 'fix',
                                schema => {
                                    custom => "com.atlassian.jira.plugin.system.customfieldtypes:select",
                                    customId => 11883,
                                    type => "string",
                                },
                            },
                            customfield_12685 => {
                                allowedValues => [
                                    {
                                        id => 13869,
                                        self => "https://jordan.corporate.local/jira/rest/api/2/customFieldOption/13869",
                                        value => "WS",
                                    },
                                    {
                                        id => 13870,
                                        self => "https://jordan.corporate.local/jira/rest/api/2/customFieldOption/13870",
                                        value => "MW",
                                    },
                                    {
                                        id => 13871,
                                        self => "https://jordan.corporate.local/jira/rest/api/2/customFieldOption/13871",
                                        value => "AG",
                                    },
                                    {
                                        id => 13872,
                                        self => "https://jordan.corporate.local/jira/rest/api/2/customFieldOption/13872",
                                        value => "DB",
                                    },
                                ],
                                hasDefaultValue => 'fix',
                                name => "NBX Tiers",
                                operations => ["add", "set", "remove"],
                                required => 'fix',
                                schema => {
                                    custom   => "com.atlassian.jira.plugin.system.customfieldtypes:multicheckboxes",
                                    customId => 12685,
                                    items    => "string",
                                    type     => "array",
                                },
                            },
                            customfield_12885 => {
                                hasDefaultValue => 'fix',
                                name => "Reviewers",
                                operations => ["add", "set", "remove"],
                                required => 'fix',
                                schema => {
                                    custom   => "com.atlassian.jira.plugin.system.customfieldtypes:multiuserpicker",
                                    customId => 12885,
                                    items    => "user",
                                    type     => "array",
                                },
                            },
                            description => {
                                hasDefaultValue => 'fix',
                                name => "Description",
                                operations => ["set"],
                                required => 'fix',
                                schema => { system => "description", type => "string" },
                            },
                            duedate => {
                                hasDefaultValue => 'fix',
                                name => "Due Date",
                                operations => ["set"],
                                required => 'fix',
                                schema => { system => "duedate", type => "date" },
                            },
                            issuetype => {
                                allowedValues => [
                                    {
                                        description => "A task that needs to be done.",
                                        id => 3,
                                        name => "Task",
                                        self => "https://my.jira.server/rest/api/2/issuetype/3",
                                        subtask => 'fix',
                                    },
                                ],
                                hasDefaultValue => 'fix',
                                name => "Issue Type",
                                operations => [],
                                required => 'fix',
                                schema => { system => "issuetype", type => "issuetype" },
                            },
                            labels => {
                                hasDefaultValue => 'fix',
                                name => "Labels",
                                operations => ["add", "set", "remove"],
                                required => 'fix',
                                schema => { items => "string", system => "labels", type => "array" },
                            },
                            priority => {
                                allowedValues => [
                                    {
                                        id => 5,
                                        name => "0 - To be prioritized",
                                        self => "https://my.jira.server/rest/api/2/priority/5",
                                    },
                                    {
                                        id => 1,
                                        name => "1 - Critical",
                                        self => "https://my.jira.server/rest/api/2/priority/1",
                                    },
                                    {
                                        id => 2,
                                        name => "2- High",
                                        self => "https://my.jira.server/rest/api/2/priority/2",
                                    },
                                    {
                                        id => 3,
                                        name => "3 - Medium",
                                        self => "https://my.jira.server/rest/api/2/priority/3",
                                    },
                                    {
                                        id => 4,
                                        name => "4 - Low",
                                        self => "https://my.jira.server/rest/api/2/priority/4",
                                    },
                                ],
                                hasDefaultValue => 'fix',
                                name => "Priority",
                                operations => ["set"],
                                required => 'fix',
                                schema => { system => "priority", type => "priority" },
                            },
                            project => {
                                allowedValues => [
                                    {
                                        id => 11083,
                                        key => "CBGOPS",
                                        name => "Cambridge IT Operations",
                                        self => "https://my.jira.server/rest/api/2/project/11083",
                                    },
                                ],
                                hasDefaultValue => 'fix',
                                name => "Project",
                                operations => ["set"],
                                required => 'fix',
                                schema => { system => "project", type => "project" },
                            },
                            reporter => {
                                hasDefaultValue => 'fix',
                                name => "Reporter",
                                operations => ["set"],
                                required => 'fix',
                                schema => { system => "reporter", type => "user" },
                            },
                            summary => {
                                hasDefaultValue => 'fix',
                                name => "Summary",
                                operations => ["set"],
                                required => 'fix',
                                schema => { system => "summary", type => "string" },
                            },
                            customfield_11883 => {
                                allowedValues => [
                                    {
                                        id => 13098,
                                        self => "https://jordan.corporate.local/jira/rest/api/2/customFieldOption/13098",
                                        value => "Network",
                                    },
                                    {
                                        id => 13099,
                                        self => "https://jordan.corporate.local/jira/rest/api/2/customFieldOption/13099",
                                        value => "Windows",
                                    },
                                    {
                                               id => 13101,
                                               self => "https://jordan.corporate.local/jira/rest/api/2/customFieldOption/13101",
                                               value => "Linux / Unix",
                                           },
                                    {
                                        id => 13100,
                                        self => "https://jordan.corporate.local/jira/rest/api/2/customFieldOption/13100",
                                        value => "Storage",
                                    }
                                        ,
                                    {
                                        id => 13107,
                                        self => "https://jordan.corporate.local/jira/rest/api/2/customFieldOption/13107",
                                        value => "DevOps",
                                    },
                                    {
                                        id => 13108,
                                        self => "https://jordan.corporate.local/jira/rest/api/2/customFieldOption/13108",
                                        value => "DBA",
                                    },
                                    {
                                        id => 13492,
                                        self => "https://jordan.corporate.local/jira/rest/api/2/customFieldOption/13492",
                                        value => "DC",
                                    },
                                    {
                                        id => 13493,
                                        self => "https://jordan.corporate.local/jira/rest/api/2/customFieldOption/13493",
                                        value => "VMWare",
                                    },
                                    {
                                        id => 13494,
                                        self => "https://jordan.corporate.local/jira/rest/api/2/customFieldOption/13494",
                                        value => "Monitoring",
                                    },
                                    {
                                        id => 13495,
                                        self => "https://jordan.corporate.local/jira/rest/api/2/customFieldOption/13495",
                                        value => "Backup",
                                    },
                                    {
                                        id => 13600,
                                        self => "https://jordan.corporate.local/jira/rest/api/2/customFieldOption/13600",
                                        value => "Architect",
                                    },
                                    {
                                        id => 13601,
                                        self => "https://jordan.corporate.local/jira/rest/api/2/customFieldOption/13601",
                                        value => "Infosec",
                                    },
                                    {
                                        id => 13602,
                                        self => "https://jordan.corporate.local/jira/rest/api/2/customFieldOption/13602",
                                        value => "Management",
                                    },
                                    {
                                        id => 13603,
                                        self => "https://jordan.corporate.local/jira/rest/api/2/customFieldOption/13603",
                                        value => "Jira Admin",
                                    },
                                    {
                                        id => 13861,
                                        self => "https://jordan.corporate.local/jira/rest/api/2/customFieldOption/13861",
                                        value => "VOIP",
                                    },
                                ],
                                hasDefaultValue => 'fix',
                                name => "Group",
                                operations => ["set"],
                                required => 'fix',
                                schema => {
                                    custom => "com.atlassian.jira.plugin.system.customfieldtypes:select",
                                    customId => 11883,
                                    type => "string",
                                },
                            },
                        },
                        id          => 3,
                        name        => "Task",
                        self        => "https://my.jira.server/rest/api/2/issuetype/3",
                        subtask     => bless(do{\(my $o = 0)}, "JSON::XS::Boolean"),
                    },
                ],
                key => "MyProject",
                name => "My project",
                self => "https://my.jira.server/rest/api/2/project/11083",
            },
        ],
    };

    return $a;
}

sub _get_issue {
    return {
        expand => "renderedFields,names,schema,transitions,operations,editmeta,changelog",
        fields => {
            customfield_10000 => [
                {
                    id => 10000,
                    self => "https://my.jira.server/rest/api/2/customFieldOption/10000",
                    value => "Impediment",
                },
            ],
            customfield_10980 => undef,
            customfield_10380 => '123456',
            customfield_11882 => {
                id => 13095,
                self => "https://my.jira.server/rest/api/2/customFieldOption/13095",
                value => "Standard",
            },
            customfield_11883 => {
                id => 13107,
                self => "https://my.jira.server/rest/api/2/customFieldOption/13107",
                value => "DevOps",
            },
            customfield_12885 => undef,
            customfield_12685 => [
                {
                    id => 13869,
                    self => "https://jordan.corporate.local/jira/rest/api/2/customFieldOption/13869",
                    value => "WS",
                },
                {
                    id => 13870,
                    self => "https://jordan.corporate.local/jira/rest/api/2/customFieldOption/13870",
                    value => "MW",
                },
                {
                    id => 13872,
                    self => "https://jordan.corporate.local/jira/rest/api/2/customFieldOption/13872",
                    value => "AG",
                },
            ],
            description => 'Created by JIRA::Client::Automated Test Script automatically.',
            issuetype => {
                description => "A task that needs to be done.",
                iconUrl => "https://my.jira.server/images/icons/issuetypes/task.png",
                id => 3,
                name => "Task",
                self => "https://my.jira.server/rest/api/2/issuetype/3",
                subtask => bless(do{\(my $o = 0)}, "JSON::XS::Boolean"),
            },
            project => {
                id => 12881,
                key => "MyProject",
                name => "My Project",
                self => "https://my.jira.server/rest/api/2/project/12881",
            },
            status => {
                description => "This issue is being actively worked on at the moment by the assignee.",
                iconUrl => "https://my.jira.server/images/icons/statuses/inprogress.png",
                id => 3,
                name => "In Development",
                self => "https://my.jira.server/rest/api/2/status/3",
                statusCategory => {
                    colorName => "yellow",
                    id => 4,
                    key => "indeterminate",
                    name => "In Progress",
                    self => "https://my.jira.server/rest/api/2/statuscategory/4",
                },
            },
            summary => 'JIRA::Client::Automated Test Script',
        },
        id => 499114,
        key => "MyProject-123",
        self => "https://my.jira.server/rest/api/latest/issue/499114",
    };
}