Skip to content

Commit 274027e

Browse files
authored
Merge pull request #1521 from NixOS/download-regression
Fix download regression
2 parents a329537 + 990fe22 commit 274027e

File tree

5 files changed

+86
-12
lines changed

5 files changed

+86
-12
lines changed

src/lib/Hydra/Controller/Build.pm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ sub checkPath {
212212
sub serveFile {
213213
my ($c, $path) = @_;
214214

215-
my $res = run(cmd => ["nix", "--experimental-features", "nix-command",
215+
my $res = runCommand(cmd => ["nix", "--experimental-features", "nix-command",
216216
"ls-store", "--store", getStoreUri(), "--json", "$path"]);
217217

218218
if ($res->{status}) {

src/lib/Hydra/Helper/Nix.pm

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ our @EXPORT = qw(
4444
readNixFile
4545
registerRoot
4646
restartBuilds
47-
run
47+
runCommand
4848
$MACHINE_LOCAL_STORE
4949
);
5050

@@ -466,7 +466,7 @@ sub readIntoSocket{
466466

467467

468468

469-
sub run {
469+
sub runCommand {
470470
my (%args) = @_;
471471
my $res = { stdout => "", stderr => "" };
472472
my $stdin = "";
@@ -506,7 +506,7 @@ sub run {
506506

507507
sub grab {
508508
my (%args) = @_;
509-
my $res = run(%args, grabStderr => 0);
509+
my $res = runCommand(%args, grabStderr => 0);
510510
if ($res->{status}) {
511511
my $msgloc = "(in an indeterminate location)";
512512
if (defined $args{dir}) {

src/lib/Hydra/Plugin/DarcsInput.pm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ sub fetchInput {
3232
my $stdout = ""; my $stderr = ""; my $res;
3333
if (! -d $clonePath) {
3434
# Clone the repository.
35-
$res = run(timeout => 600,
35+
$res = runCommand(timeout => 600,
3636
cmd => ["darcs", "get", "--lazy", $uri, $clonePath],
3737
dir => $ENV{"TMPDIR"});
3838
die "Error getting darcs repo at `$uri':\n$stderr" if $res->{status};

src/lib/Hydra/Plugin/GitInput.pm

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -137,35 +137,35 @@ sub fetchInput {
137137
my $res;
138138
if (! -d $clonePath) {
139139
# Clone everything and fetch the branch.
140-
$res = run(cmd => ["git", "init", $clonePath]);
141-
$res = run(cmd => ["git", "remote", "add", "origin", "--", $uri], dir => $clonePath) unless $res->{status};
140+
$res = runCommand(cmd => ["git", "init", $clonePath]);
141+
$res = runCommand(cmd => ["git", "remote", "add", "origin", "--", $uri], dir => $clonePath) unless $res->{status};
142142
die "error creating git repo in `$clonePath':\n$res->{stderr}" if $res->{status};
143143
}
144144

145145
# This command forces the update of the local branch to be in the same as
146146
# the remote branch for whatever the repository state is. This command mirrors
147147
# only one branch of the remote repository.
148148
my $localBranch = _isHash($branch) ? "_hydra_tmp" : $branch;
149-
$res = run(cmd => ["git", "fetch", "-fu", "origin", "+$branch:$localBranch"], dir => $clonePath,
149+
$res = runCommand(cmd => ["git", "fetch", "-fu", "origin", "+$branch:$localBranch"], dir => $clonePath,
150150
timeout => $cfg->{timeout});
151-
$res = run(cmd => ["git", "fetch", "-fu", "origin"], dir => $clonePath, timeout => $cfg->{timeout}) if $res->{status};
151+
$res = runCommand(cmd => ["git", "fetch", "-fu", "origin"], dir => $clonePath, timeout => $cfg->{timeout}) if $res->{status};
152152
die "error fetching latest change from git repo at `$uri':\n$res->{stderr}" if $res->{status};
153153

154154
# If deepClone is defined, then we look at the content of the repository
155155
# to determine if this is a top-git branch.
156156
if (defined $deepClone) {
157157

158158
# Is the target branch a topgit branch?
159-
$res = run(cmd => ["git", "ls-tree", "-r", "$branch", ".topgit"], dir => $clonePath);
159+
$res = runCommand(cmd => ["git", "ls-tree", "-r", "$branch", ".topgit"], dir => $clonePath);
160160

161161
if ($res->{stdout} ne "") {
162162
# Checkout the branch to look at its content.
163-
$res = run(cmd => ["git", "checkout", "--force", "$branch"], dir => $clonePath);
163+
$res = runCommand(cmd => ["git", "checkout", "--force", "$branch"], dir => $clonePath);
164164
die "error checking out Git branch '$branch' at `$uri':\n$res->{stderr}" if $res->{status};
165165

166166
# This is a TopGit branch. Fetch all the topic branches so
167167
# that builders can run "tg patch" and similar.
168-
$res = run(cmd => ["tg", "remote", "--populate", "origin"], dir => $clonePath, timeout => $cfg->{timeout});
168+
$res = runCommand(cmd => ["tg", "remote", "--populate", "origin"], dir => $clonePath, timeout => $cfg->{timeout});
169169
print STDERR "warning: `tg remote --populate origin' failed:\n$res->{stderr}" if $res->{status};
170170
}
171171
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
use strict;
2+
use warnings;
3+
use Setup;
4+
use Test2::V0;
5+
use Catalyst::Test ();
6+
use HTTP::Request::Common;
7+
8+
my %ctx = test_init();
9+
10+
Catalyst::Test->import('Hydra');
11+
12+
my $db = Hydra::Model::DB->new;
13+
hydra_setup($db);
14+
15+
my $project = $db->resultset('Projects')->create({name => "tests", displayname => "", owner => "root"});
16+
17+
# Create a simple Nix expression that uses the existing build-product-simple.sh
18+
my $jobsdir = $ctx{jobsdir};
19+
my $nixfile = "$jobsdir/simple.nix";
20+
open(my $fh, '>', $nixfile) or die "Cannot create simple.nix: $!";
21+
print $fh <<"EOF";
22+
with import ./config.nix;
23+
{
24+
simple = mkDerivation {
25+
name = "build-product-simple";
26+
builder = ./build-product-simple.sh;
27+
};
28+
}
29+
EOF
30+
close($fh);
31+
32+
# Create a jobset that uses the simple build
33+
my $jobset = createBaseJobset("simple", "simple.nix", $ctx{jobsdir});
34+
35+
ok(evalSucceeds($jobset), "Evaluating simple.nix should succeed");
36+
is(nrQueuedBuildsForJobset($jobset), 1, "Should have 1 build queued");
37+
38+
my $build = (queuedBuildsForJobset($jobset))[0];
39+
ok(runBuild($build), "Build should succeed");
40+
41+
$build->discard_changes();
42+
43+
subtest "Test downloading build products (regression test for #1520)" => sub {
44+
# Get the build URL
45+
my $build_id = $build->id;
46+
47+
# First, check that the build has products
48+
my @products = $build->buildproducts;
49+
ok(scalar @products >= 1, "Build should have at least 1 product");
50+
51+
# Find the doc product (created by build-product-simple.sh)
52+
my ($doc_product) = grep { $_->type eq "doc" } @products;
53+
ok($doc_product, "Should have a doc product");
54+
55+
if ($doc_product) {
56+
# Test downloading via the download endpoint
57+
# This tests the serveFile function which was broken in #1520
58+
my $download_url = "/build/$build_id/download/" . $doc_product->productnr . "/text.txt";
59+
my $response = request(GET $download_url);
60+
61+
# The key test: should not return 500 error with "Can't use string ("1") as a HASH ref"
62+
isnt($response->code, 500, "Download should not return 500 error (regression test for #1520)");
63+
is($response->code, 200, "Download should succeed with 200")
64+
or diag("Response code: " . $response->code . ", Content: " . $response->content);
65+
66+
like($response->header('Content-Security-Policy') // '', qr/\bsandbox\b/, 'CSP header present with sandbox');
67+
68+
# Check that we get actual content
69+
ok(length($response->content) > 0, "Should receive file content");
70+
is($response->content, "Hello\n", "Should get expected content");
71+
}
72+
};
73+
74+
done_testing();

0 commit comments

Comments
 (0)