From dd6cd33e98636812ef69f7c95aecacfa322834c7 Mon Sep 17 00:00:00 2001 From: Graham Christensen Date: Wed, 28 Apr 2021 18:17:53 -0400 Subject: [PATCH 1/8] move the api-test.nix in to the jobsdir --- t/{ => jobs}/api-test.nix | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename t/{ => jobs}/api-test.nix (100%) diff --git a/t/api-test.nix b/t/jobs/api-test.nix similarity index 100% rename from t/api-test.nix rename to t/jobs/api-test.nix From 38c7f88b7c2f0fc867648bfcdcf6407978e35df1 Mon Sep 17 00:00:00 2001 From: Graham Christensen Date: Wed, 28 Apr 2021 18:18:53 -0400 Subject: [PATCH 2/8] rename api-test.pl to .t so it runs under yath --- t/{api-test.pl => api-test.t} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename t/{api-test.pl => api-test.t} (100%) diff --git a/t/api-test.pl b/t/api-test.t similarity index 100% rename from t/api-test.pl rename to t/api-test.t From 20df86c2756c7b7ddcd26aaa7f95ee9b68dcdbd8 Mon Sep 17 00:00:00 2001 From: Graham Christensen Date: Wed, 28 Apr 2021 18:24:24 -0400 Subject: [PATCH 3/8] api-test.t: make it work under yath 1. Configure the in-memory Hydra instance with a null path input cache time to avoid caching slowing the test down. 2. Use the Catalyst::Test helpers so we talk to the application and skip needing to actually run a webserver. 3. Change path references to use a tempdir, since this is running while other tests are also running. 4. Change the login flow to save a cookie and pass it manually. A bit weird, but it avoids a dependency on heavier browser-mimicking libraries. --- t/api-test.t | 65 ++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 53 insertions(+), 12 deletions(-) diff --git a/t/api-test.t b/t/api-test.t index b07321ea..556b28a7 100644 --- a/t/api-test.t +++ b/t/api-test.t @@ -1,19 +1,51 @@ -use LWP::UserAgent; +use strict; +use Setup; use JSON; -use Test::Simple tests => 20; +use File::Copy; -my $ua = LWP::UserAgent->new; -$ua->cookie_jar({}); +my %ctx = test_init( + hydra_config => q| +# No caching for PathInput plugin, otherwise we get wrong values +# (as it has a 30s window where no changes to the file are considered). +path_input_cache_validity_seconds = 0 +| +); + + +my $jobsetdir = $ctx{tmpdir} . '/jobset'; +mkdir($jobsetdir); +copy($ctx{jobsdir} . '/api-test.nix', "$jobsetdir/default.nix"); + +require Hydra::Schema; +use HTTP::Request::Common; + +use Test2::V0; +require Catalyst::Test; +Catalyst::Test->import('Hydra'); + +my $db = Hydra::Model::DB->new; +hydra_setup($db); + +{ + my $user = $db->resultset('Users')->find({ username => 'root' }); + $user->setPassword('foobar'); + $user->userroles->update_or_create({ role => 'admin' }); +} + +my $cookie = ""; sub request_json { my ($opts) = @_; my $req = HTTP::Request->new; $req->method($opts->{method} or "GET"); - $req->uri("http://localhost:3000$opts->{uri}"); + $req->uri("http://localhost$opts->{uri}"); $req->header(Accept => "application/json"); - $req->header(Referer => "http://localhost:3000/") if $opts->{method} eq "POST"; + $req->header(Content_Type => "application/json"); + $req->header(Origin => "http://localhost/") if $opts->{method} eq "POST"; + $req->header(Cookie => $cookie); + $req->content(encode_json($opts->{data})) if defined $opts->{data}; - my $res = $ua->request($req); + my $res = request($req); print $res->as_string(); return $res; } @@ -27,6 +59,7 @@ my $user = decode_json($result->content()); ok($user->{username} eq "root", "The root user is named root"); ok($user->{userroles}->[0] eq "admin", "The root user is an admin"); +$cookie = $result->header("set-cookie"); $user = decode_json(request_json({ uri => "/current-user" })->content()); ok($user->{username} eq "root", "The current user is named root"); @@ -41,23 +74,29 @@ my $project = decode_json(request_json({ uri => '/project/sample' })->content()) ok((not @{$project->{jobsets}}), "A new project has no jobsets"); -$result = request_json({ uri => '/jobset/sample/default', method => 'PUT', data => { nixexprpath => "default.nix", nixexprinput => "my-src", inputs => { "my-src" => { type => "path", value => "/run/jobset" } }, enabled => "1", visible => "1", checkinterval => "3600"} }); +$result = request_json({ uri => '/jobset/sample/default', method => 'PUT', data => { nixexprpath => "default.nix", nixexprinput => "my-src", inputs => { "my-src" => { type => "path", value => $jobsetdir } }, enabled => "1", visible => "1", checkinterval => "3600"} }); ok($result->code() == 201, "PUTting a new jobset creates it"); my $jobset = decode_json(request_json({ uri => '/jobset/sample/default' })->content()); ok(exists $jobset->{jobsetinputs}->{"my-src"}, "The new jobset has a 'my-src' input"); -ok($jobset->{jobsetinputs}->{"my-src"}->{jobsetinputalts}->[0] eq "/run/jobset", "The 'my-src' input is in /run/jobset"); +ok($jobset->{jobsetinputs}->{"my-src"}->{"jobsetinputalts"}->[0] eq $jobsetdir, "The 'my-src' input is in $jobsetdir"); + +ok(evalSucceeds($db->resultset('Jobsets')->find({ name => 'default' })), "Evaluating should exit with return code 0"); -system("hydra-eval-jobset sample default"); $result = request_json({ uri => '/jobset/sample/default/evals' }); ok($result->code() == 200, "Can get evals of a jobset"); my $evals = decode_json($result->content())->{evals}; my $eval = $evals->[0]; ok($eval->{hasnewbuilds} == 1, "The first eval of a jobset has new builds"); -system("echo >> /run/jobset/default.nix; hydra-eval-jobset sample default"); + +open(my $fh, ">>", "${jobsetdir}/default.nix") or die "didn't open?"; +say $fh "\n"; +close $fh; +ok(evalSucceeds($db->resultset('Jobsets')->find({ name => 'default' })), "Evaluating should exit with return code 0"); + my $evals = decode_json(request_json({ uri => '/jobset/sample/default/evals' })->content())->{evals}; ok(scalar(@$evals) == 2, "Changing a jobset source creates the second evaluation"); ok($evals->[0]->{jobsetevalinputs}->{"my-src"}->{revision} != $evals->[1]->{jobsetevalinputs}->{"my-src"}->{revision}, "Changing a jobset source changes its revision"); @@ -65,7 +104,7 @@ ok($evals->[0]->{jobsetevalinputs}->{"my-src"}->{revision} != $evals->[1]->{jobs my $build = decode_json(request_json({ uri => "/build/" . $evals->[0]->{builds}->[0] })->content()); ok($build->{job} eq "job", "The build's job name is job"); ok($build->{finished} == 0, "The build isn't finished yet"); -ok($build->{buildoutputs}->{out}->{path} =~ /^\/nix\/store\/[a-zA-Z0-9]{32}-job$/, "The build's outpath is in the Nix store and named 'job'"); +ok($build->{buildoutputs}->{out}->{path} =~ /\/nix\/store\/[a-zA-Z0-9]{32}-job$/, "The build's outpath is in the Nix store and named 'job'"); my $search_project = decode_json(request_json({ uri => "/search/?query=sample" })->content()); @@ -73,3 +112,5 @@ ok($search_project->{projects}[0]->{name} == "sample", "Search for project 'samp my $search_build = decode_json(request_json({ uri => "/search/?query=" . $build->{buildoutputs}->{out}->{path} })->content()); ok($search_build->{builds}[0]->{buildoutputs}->{out}->{path} == $build->{buildoutputs}->{out}->{path}, "Search for builds work"); + +done_testing; \ No newline at end of file From a34f23f7e67da5a9cf98fed5d8b0dfce6dd9ba1b Mon Sep 17 00:00:00 2001 From: Graham Christensen Date: Wed, 28 Apr 2021 18:27:58 -0400 Subject: [PATCH 4/8] api-test: use is for nicer errors --- t/api-test.t | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/t/api-test.t b/t/api-test.t index 556b28a7..cef07698 100644 --- a/t/api-test.t +++ b/t/api-test.t @@ -51,45 +51,45 @@ sub request_json { } my $result = request_json({ uri => "/login", method => "POST", data => { username => "root", password => "wrong" } }); -ok($result->code() == 403, "Incorrect password rejected."); +is($result->code(), 403, "Incorrect password rejected."); my $result = request_json({ uri => "/login", method => "POST", data => { username => "root", password => "foobar" } }); my $user = decode_json($result->content()); -ok($user->{username} eq "root", "The root user is named root"); -ok($user->{userroles}->[0] eq "admin", "The root user is an admin"); +is($user->{username}, "root", "The root user is named root"); +is($user->{userroles}->[0], "admin", "The root user is an admin"); $cookie = $result->header("set-cookie"); $user = decode_json(request_json({ uri => "/current-user" })->content()); -ok($user->{username} eq "root", "The current user is named root"); -ok($user->{userroles}->[0] eq "admin", "The current user is an admin"); +is($user->{username}, "root", "The current user is named root"); +is($user->{userroles}->[0], "admin", "The current user is an admin"); -ok(request_json({ uri => '/project/sample' })->code() == 404, "Non-existent projects don't exist"); +is(request_json({ uri => '/project/sample' })->code(), 404, "Non-existent projects don't exist"); $result = request_json({ uri => '/project/sample', method => 'PUT', data => { displayname => "Sample", enabled => "1", visible => "1", } }); -ok($result->code() == 201, "PUTting a new project creates it"); +is($result->code(), 201, "PUTting a new project creates it"); my $project = decode_json(request_json({ uri => '/project/sample' })->content()); ok((not @{$project->{jobsets}}), "A new project has no jobsets"); $result = request_json({ uri => '/jobset/sample/default', method => 'PUT', data => { nixexprpath => "default.nix", nixexprinput => "my-src", inputs => { "my-src" => { type => "path", value => $jobsetdir } }, enabled => "1", visible => "1", checkinterval => "3600"} }); -ok($result->code() == 201, "PUTting a new jobset creates it"); +is($result->code(), 201, "PUTting a new jobset creates it"); my $jobset = decode_json(request_json({ uri => '/jobset/sample/default' })->content()); ok(exists $jobset->{jobsetinputs}->{"my-src"}, "The new jobset has a 'my-src' input"); -ok($jobset->{jobsetinputs}->{"my-src"}->{"jobsetinputalts"}->[0] eq $jobsetdir, "The 'my-src' input is in $jobsetdir"); +is($jobset->{jobsetinputs}->{"my-src"}->{"jobsetinputalts"}->[0], $jobsetdir, "The 'my-src' input is in $jobsetdir"); ok(evalSucceeds($db->resultset('Jobsets')->find({ name => 'default' })), "Evaluating should exit with return code 0"); $result = request_json({ uri => '/jobset/sample/default/evals' }); -ok($result->code() == 200, "Can get evals of a jobset"); +is($result->code(), 200, "Can get evals of a jobset"); my $evals = decode_json($result->content())->{evals}; my $eval = $evals->[0]; -ok($eval->{hasnewbuilds} == 1, "The first eval of a jobset has new builds"); +is($eval->{hasnewbuilds}, 1, "The first eval of a jobset has new builds"); open(my $fh, ">>", "${jobsetdir}/default.nix") or die "didn't open?"; @@ -98,19 +98,19 @@ close $fh; ok(evalSucceeds($db->resultset('Jobsets')->find({ name => 'default' })), "Evaluating should exit with return code 0"); my $evals = decode_json(request_json({ uri => '/jobset/sample/default/evals' })->content())->{evals}; -ok(scalar(@$evals) == 2, "Changing a jobset source creates the second evaluation"); -ok($evals->[0]->{jobsetevalinputs}->{"my-src"}->{revision} != $evals->[1]->{jobsetevalinputs}->{"my-src"}->{revision}, "Changing a jobset source changes its revision"); +is(scalar(@$evals), 2, "Changing a jobset source creates the second evaluation"); +isnt($evals->[0]->{jobsetevalinputs}->{"my-src"}->{revision}, $evals->[1]->{jobsetevalinputs}->{"my-src"}->{revision}, "Changing a jobset source changes its revision"); my $build = decode_json(request_json({ uri => "/build/" . $evals->[0]->{builds}->[0] })->content()); -ok($build->{job} eq "job", "The build's job name is job"); -ok($build->{finished} == 0, "The build isn't finished yet"); +is($build->{job}, "job", "The build's job name is job"); +is($build->{finished}, 0, "The build isn't finished yet"); ok($build->{buildoutputs}->{out}->{path} =~ /\/nix\/store\/[a-zA-Z0-9]{32}-job$/, "The build's outpath is in the Nix store and named 'job'"); my $search_project = decode_json(request_json({ uri => "/search/?query=sample" })->content()); -ok($search_project->{projects}[0]->{name} == "sample", "Search for project 'sample' works"); +is($search_project->{projects}[0]->{name}, "sample", "Search for project 'sample' works"); my $search_build = decode_json(request_json({ uri => "/search/?query=" . $build->{buildoutputs}->{out}->{path} })->content()); -ok($search_build->{builds}[0]->{buildoutputs}->{out}->{path} == $build->{buildoutputs}->{out}->{path}, "Search for builds work"); +is($search_build->{builds}[0]->{buildoutputs}->{out}->{path}, $build->{buildoutputs}->{out}->{path}, "Search for builds work"); done_testing; \ No newline at end of file From fdb6e7dd972b0c05d13a56d215871daf4d06c2e8 Mon Sep 17 00:00:00 2001 From: Graham Christensen Date: Wed, 28 Apr 2021 18:30:35 -0400 Subject: [PATCH 5/8] fixup: return the user entity on login --- src/lib/Hydra/Controller/User.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/Hydra/Controller/User.pm b/src/lib/Hydra/Controller/User.pm index 0ce5b2ff..49c49c84 100644 --- a/src/lib/Hydra/Controller/User.pm +++ b/src/lib/Hydra/Controller/User.pm @@ -40,7 +40,7 @@ sub login_POST { $self->status_found( $c, location => $c->uri_for("current-user"), - entity => {} + entity => $c->model("DB::Users")->find($c->user->username) ); } From 5c5b53961ef6a3645f1b2c5479e68eb55f8e3737 Mon Sep 17 00:00:00 2001 From: Graham Christensen Date: Wed, 28 Apr 2021 18:30:53 -0400 Subject: [PATCH 6/8] fixup: api-test.t expected to pass inputs as inputs --- t/api-test.t | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/api-test.t b/t/api-test.t index cef07698..3b425d99 100644 --- a/t/api-test.t +++ b/t/api-test.t @@ -74,7 +74,7 @@ my $project = decode_json(request_json({ uri => '/project/sample' })->content()) ok((not @{$project->{jobsets}}), "A new project has no jobsets"); -$result = request_json({ uri => '/jobset/sample/default', method => 'PUT', data => { nixexprpath => "default.nix", nixexprinput => "my-src", inputs => { "my-src" => { type => "path", value => $jobsetdir } }, enabled => "1", visible => "1", checkinterval => "3600"} }); +$result = request_json({ uri => '/jobset/sample/default', method => 'PUT', data => { nixexprpath => "default.nix", nixexprinput => "my-src", jobsetinputs => { "my-src" => { type => "path", value => $jobsetdir } }, enabled => "1", visible => "1", checkinterval => "3600"} }); is($result->code(), 201, "PUTting a new jobset creates it"); my $jobset = decode_json(request_json({ uri => '/jobset/sample/default' })->content()); From 015d8298cbce476fa617b4c2660920c94fad86a8 Mon Sep 17 00:00:00 2001 From: Graham Christensen Date: Wed, 28 Apr 2021 18:32:23 -0400 Subject: [PATCH 7/8] flake.nix: drop the API test --- flake.nix | 39 --------------------------------------- 1 file changed, 39 deletions(-) diff --git a/flake.nix b/flake.nix index 3c6777be..017e0b20 100644 --- a/flake.nix +++ b/flake.nix @@ -456,45 +456,6 @@ ''; }; - tests.api.x86_64-linux = - with import (nixpkgs + "/nixos/lib/testing-python.nix") { system = "x86_64-linux"; }; - simpleTest { - machine = { pkgs, ... }: { - imports = [ hydraServer ]; - # No caching for PathInput plugin, otherwise we get wrong values - # (as it has a 30s window where no changes to the file are considered). - services.hydra-dev.extraConfig = '' - path_input_cache_validity_seconds = 0 - ''; - }; - testScript = - let dbi = "dbi:Pg:dbname=hydra;user=root;"; in - '' - machine.wait_for_job("hydra-init") - - # Create an admin account and some other state. - machine.succeed( - """ - su - hydra -c "hydra-create-user root --email-address 'alice@example.org' --password foobar --role admin" - mkdir /run/jobset /tmp/nix - chmod 755 /run/jobset /tmp/nix - cp ${./t/api-test.nix} /run/jobset/default.nix - chmod 644 /run/jobset/default.nix - chown -R hydra /run/jobset /tmp/nix - """ - ) - - machine.succeed("systemctl stop hydra-evaluator hydra-queue-runner") - machine.wait_for_job("hydra-server") - machine.wait_for_open_port("3000") - - # Run the API tests. - machine.succeed( - "su - hydra -c 'perl -I ${pkgs.hydra.perlDeps}/lib/perl5/site_perl ${./t/api-test.pl}' >&2" - ) - ''; - }; - tests.notifications.x86_64-linux = with import (nixpkgs + "/nixos/lib/testing-python.nix") { system = "x86_64-linux"; }; simpleTest { From a44e5b73a806656757a246a8b1e47233dcd281c9 Mon Sep 17 00:00:00 2001 From: Graham Christensen Date: Wed, 28 Apr 2021 19:41:49 -0400 Subject: [PATCH 8/8] api-test: clean up, use subtests --- t/api-test.t | 111 +++++++++++++++++++++++++++++---------------------- 1 file changed, 63 insertions(+), 48 deletions(-) diff --git a/t/api-test.t b/t/api-test.t index 3b425d99..cca28243 100644 --- a/t/api-test.t +++ b/t/api-test.t @@ -50,67 +50,82 @@ sub request_json { return $res; } -my $result = request_json({ uri => "/login", method => "POST", data => { username => "root", password => "wrong" } }); -is($result->code(), 403, "Incorrect password rejected."); +subtest "login" => sub { + subtest "bad password" => sub { + my $result = request_json({ uri => "/login", method => "POST", data => { username => "root", password => "wrong" } }); + is($result->code(), 403, "Incorrect password rejected."); + }; -my $result = request_json({ uri => "/login", method => "POST", data => { username => "root", password => "foobar" } }); + my $result = request_json({ uri => "/login", method => "POST", data => { username => "root", password => "foobar" } }); -my $user = decode_json($result->content()); + my $user = decode_json($result->content()); -is($user->{username}, "root", "The root user is named root"); -is($user->{userroles}->[0], "admin", "The root user is an admin"); -$cookie = $result->header("set-cookie"); + is($user->{username}, "root", "The root user is named root"); + is($user->{userroles}->[0], "admin", "The root user is an admin"); + $cookie = $result->header("set-cookie"); -$user = decode_json(request_json({ uri => "/current-user" })->content()); -is($user->{username}, "root", "The current user is named root"); -is($user->{userroles}->[0], "admin", "The current user is an admin"); + $user = decode_json(request_json({ uri => "/current-user" })->content()); + is($user->{username}, "root", "The current user is named root"); + is($user->{userroles}->[0], "admin", "The current user is an admin"); +}; -is(request_json({ uri => '/project/sample' })->code(), 404, "Non-existent projects don't exist"); +subtest "projects" => sub { + is(request_json({ uri => '/project/sample' })->code(), 404, "Non-existent projects don't exist"); -$result = request_json({ uri => '/project/sample', method => 'PUT', data => { displayname => "Sample", enabled => "1", visible => "1", } }); -is($result->code(), 201, "PUTting a new project creates it"); + my $result = request_json({ uri => '/project/sample', method => 'PUT', data => { displayname => "Sample", enabled => "1", visible => "1", } }); + is($result->code(), 201, "PUTting a new project creates it"); -my $project = decode_json(request_json({ uri => '/project/sample' })->content()); + my $project = decode_json(request_json({ uri => '/project/sample' })->content()); -ok((not @{$project->{jobsets}}), "A new project has no jobsets"); + ok((not @{$project->{jobsets}}), "A new project has no jobsets"); +}; -$result = request_json({ uri => '/jobset/sample/default', method => 'PUT', data => { nixexprpath => "default.nix", nixexprinput => "my-src", jobsetinputs => { "my-src" => { type => "path", value => $jobsetdir } }, enabled => "1", visible => "1", checkinterval => "3600"} }); -is($result->code(), 201, "PUTting a new jobset creates it"); +subtest "jobsets" => sub { + my $result = request_json({ uri => '/jobset/sample/default', method => 'PUT', data => { nixexprpath => "default.nix", nixexprinput => "my-src", jobsetinputs => { "my-src" => { type => "path", value => $jobsetdir } }, enabled => "1", visible => "1", checkinterval => "3600"} }); + is($result->code(), 201, "PUTting a new jobset creates it"); -my $jobset = decode_json(request_json({ uri => '/jobset/sample/default' })->content()); + my $jobset = decode_json(request_json({ uri => '/jobset/sample/default' })->content()); -ok(exists $jobset->{jobsetinputs}->{"my-src"}, "The new jobset has a 'my-src' input"); + ok(exists $jobset->{jobsetinputs}->{"my-src"}, "The new jobset has a 'my-src' input"); -is($jobset->{jobsetinputs}->{"my-src"}->{"jobsetinputalts"}->[0], $jobsetdir, "The 'my-src' input is in $jobsetdir"); + is($jobset->{jobsetinputs}->{"my-src"}->{"jobsetinputalts"}->[0], $jobsetdir, "The 'my-src' input is in $jobsetdir"); +}; -ok(evalSucceeds($db->resultset('Jobsets')->find({ name => 'default' })), "Evaluating should exit with return code 0"); +subtest "evaluation" => sub { + subtest "initial evaluaton" => sub { + ok(evalSucceeds($db->resultset('Jobsets')->find({ name => 'default' })), "Evaluating should exit with return code 0"); -$result = request_json({ uri => '/jobset/sample/default/evals' }); -is($result->code(), 200, "Can get evals of a jobset"); -my $evals = decode_json($result->content())->{evals}; -my $eval = $evals->[0]; -is($eval->{hasnewbuilds}, 1, "The first eval of a jobset has new builds"); + my $result = request_json({ uri => '/jobset/sample/default/evals' }); + is($result->code(), 200, "Can get evals of a jobset"); + my $evals = decode_json($result->content())->{evals}; + my $eval = $evals->[0]; + is($eval->{hasnewbuilds}, 1, "The first eval of a jobset has new builds"); + }; + + subtest "second evaluation" => sub { + open(my $fh, ">>", "${jobsetdir}/default.nix") or die "didn't open?"; + say $fh "\n"; + close $fh; + ok(evalSucceeds($db->resultset('Jobsets')->find({ name => 'default' })), "Evaluating should exit with return code 0"); + + my $evals = decode_json(request_json({ uri => '/jobset/sample/default/evals' })->content())->{evals}; + is(scalar(@$evals), 2, "Changing a jobset source creates the second evaluation"); + isnt($evals->[0]->{jobsetevalinputs}->{"my-src"}->{revision}, $evals->[1]->{jobsetevalinputs}->{"my-src"}->{revision}, "Changing a jobset source changes its revision"); + + my $build = decode_json(request_json({ uri => "/build/" . $evals->[0]->{builds}->[0] })->content()); + is($build->{job}, "job", "The build's job name is job"); + is($build->{finished}, 0, "The build isn't finished yet"); + ok($build->{buildoutputs}->{out}->{path} =~ /\/nix\/store\/[a-zA-Z0-9]{32}-job$/, "The build's outpath is in the Nix store and named 'job'"); + + subtest "search" => sub { + my $search_project = decode_json(request_json({ uri => "/search/?query=sample" })->content()); + is($search_project->{projects}[0]->{name}, "sample", "Search for project 'sample' works"); + + my $search_build = decode_json(request_json({ uri => "/search/?query=" . $build->{buildoutputs}->{out}->{path} })->content()); + is($search_build->{builds}[0]->{buildoutputs}->{out}->{path}, $build->{buildoutputs}->{out}->{path}, "Search for builds work"); + }; + }; +}; -open(my $fh, ">>", "${jobsetdir}/default.nix") or die "didn't open?"; -say $fh "\n"; -close $fh; -ok(evalSucceeds($db->resultset('Jobsets')->find({ name => 'default' })), "Evaluating should exit with return code 0"); - -my $evals = decode_json(request_json({ uri => '/jobset/sample/default/evals' })->content())->{evals}; -is(scalar(@$evals), 2, "Changing a jobset source creates the second evaluation"); -isnt($evals->[0]->{jobsetevalinputs}->{"my-src"}->{revision}, $evals->[1]->{jobsetevalinputs}->{"my-src"}->{revision}, "Changing a jobset source changes its revision"); - -my $build = decode_json(request_json({ uri => "/build/" . $evals->[0]->{builds}->[0] })->content()); -is($build->{job}, "job", "The build's job name is job"); -is($build->{finished}, 0, "The build isn't finished yet"); -ok($build->{buildoutputs}->{out}->{path} =~ /\/nix\/store\/[a-zA-Z0-9]{32}-job$/, "The build's outpath is in the Nix store and named 'job'"); - - -my $search_project = decode_json(request_json({ uri => "/search/?query=sample" })->content()); -is($search_project->{projects}[0]->{name}, "sample", "Search for project 'sample' works"); - -my $search_build = decode_json(request_json({ uri => "/search/?query=" . $build->{buildoutputs}->{out}->{path} })->content()); -is($search_build->{builds}[0]->{buildoutputs}->{out}->{path}, $build->{buildoutputs}->{out}->{path}, "Search for builds work"); - -done_testing; \ No newline at end of file +done_testing;