agama/service/test/integration/profile_itest.rb
2026-07-01 14:40:21 +02:00

266 lines
7.8 KiB
Ruby

# frozen_string_literal: true
# See ./README.md for standalone usage
# TODO: remember to set up and test the --host option after all
require "cheetah"
require "json"
require "webrick"
# @param filename relative to git repo root
# @return usable for this suite
def fixture(filename)
# the tests specify the paths relative to repo root
# but we run in service/
"../" + filename
end
# @param filename relative to git repo root
# @return usable for this suite, absolute
def abs_fixture(filename)
File.absolute_path(fixture(filename))
end
def cheetah_kwargs
{
stdout: :capture,
stderr: :capture,
allowed_exitstatus: 0..255
}
end
WEB_SERVER_PORT = 8000
# @return [HTTPServer]
def web_server_start
root = abs_fixture(".")
server = WEBrick::HTTPServer.new(Port: WEB_SERVER_PORT, DocumentRoot: root)
Thread.new { server.start }
server
end
def web_server_shutdown(server)
server.shutdown
end
# needs declarations:
# command [Array<String>] like ["agama", "profile", "validate"]
shared_examples "accepts input in 3 ways" do |filename, stdout_match, stderr_match,
exitcode_match = 0|
context "with #{filename} as path" do
it "output matches" do
cmd = [*command, fixture(filename)]
stdout, stderr, exitcode = Cheetah.run(*cmd, **cheetah_kwargs)
expect(stdout).to include(stdout_match)
expect(stderr).to include(stderr_match)
expect(exitcode).to eq exitcode_match
end
end
context "with #{filename} as http URL" do
it "output matches" do
url = "http://localhost:#{WEB_SERVER_PORT}/#{filename}"
cmd = [*command, url]
stdout, stderr = Cheetah.run(*cmd, **cheetah_kwargs)
expect(stdout).to include(stdout_match)
expect(stderr).to include(stderr_match)
end
end
context "with #{filename} as stdin" do
it "output matches" do
input = File.read(fixture(filename))
cmd = [*command, "-"]
stdout, stderr = Cheetah.run(*cmd, stdin: input, **cheetah_kwargs)
expect(stdout).to include(stdout_match)
expect(stderr).to include(stderr_match)
end
end
end
shared_examples "JSON output structurally matches trivial_tw" do
it "JSON output structurally matches trivial_tw" do
parsed_output = JSON.parse(output)
expect(parsed_output["product"]["id"]).to eq "Tumbleweed"
expect(parsed_output["software"]["patterns"]).to eq ["base"]
expect(parsed_output["software"]["packages"]).to eq []
end
end
describe "agama config" do
before(:all) do
@web_server = web_server_start
end
after(:all) do
web_server_shutdown(@web_server)
end
describe "validate:" do
let(:command) { ["agama", "config", "validate"] }
context "valid profile" do
include_examples \
"accepts input in 3 ways", \
"rust/share/examples/profile_tw_minimal.json", \
"", \
""
end
context "valid profile with space in path" do
include_examples \
"accepts input in 3 ways", \
"rust/share/examples space/profile_tw_minimal.json", \
"", \
""
end
# Rust Url library will see the percent
# and wrongly think that the path does not need escaping.
# This is a bug but its impact is low.
xcontext "valid profile with percent in path" do
include_examples \
"accepts input in 3 ways", \
"rust/share/examples%20percent/profile_tw_minimal.json", \
"", \
""
end
context "invalid profile" do
include_examples \
"accepts input in 3 ways", \
"rust/share/examples/profile_tw_invalid.json", \
"", \
"Additional properties are not allowed ('ID' was unexpected). /product", \
1
end
end
describe "generate:" do
context "config via stdin contains relative URL references:" do
let(:profile_body) do
json = <<~JSON
{
"scripts": {
"postPartitioning": [
{
"name": "foo",
"url": "my-script.sh"
}
]
}
}
JSON
json
end
it "they are resolved" do
output = Cheetah.run("agama", "config", "generate", "-",
stdout: :capture, stdin: profile_body)
expect(output).to include("file:///")
expect(output).to include("/service/my-script.sh")
end
end
context "config via file contains relative URL references:" do
let(:filename) { "rust/share/examples/post-script-ref.jsonnet" }
it "they are resolved" do
output = Cheetah.run("agama", "config", "generate", fixture(filename),
stdout: :capture)
expect(output).to include("file:///")
expect(output).to include("/rust/share/examples/enable-sshd.sh")
expect(output).to_not include("..")
end
end
context "jsonnet valid (by stdin)" do
let(:profile_body) { '{product: {id: "Tumbleweed"}}' }
it "is evaluated and validity reported" do
stdout, stderr = Cheetah.run("agama", "config", "generate", "-",
stdout: :capture, stderr: :capture, stdin: profile_body)
expected = <<~JSON
{
"product": {
"id": "Tumbleweed"
}
}
JSON
expect(stdout).to eq(expected)
# another test is that cheetah do not raise as invalid generate return non-zero
end
end
context "jsonnet invalid (by stdin)" do
let(:profile_body) { '{product: {uh: "oh"}}' }
it "is evaluated and invalidity reported" do
stdout, stderr = Cheetah.run("agama", "config", "generate", "-",
stdout: :capture, stderr: :capture, stdin: profile_body, allowed_exitstatus: 1)
# NOTE: 3 space indent here
expected = <<~JSON
{
"product": {
"uh": "oh"
}
}
JSON
expect(stdout).to eq(expected)
expect(stderr).to include("Schema validation failed")
expect(stderr).to include("'uh' was unexpected")
expect(stderr).to include("\"id\" is a required property")
end
end
end
describe "generate (autoyast):" do
let(:command) { ["agama", "config", "generate"] }
# I want to test that YaST special schemes like label:
# are handled, but unable to make them work in my testing environment
xcontext "XML, with a YaST special URL" do
let(:filename) { "service/test/fixtures/profiles/trivial_tw.xml" }
let(:label_url) { "label://mylabel#{abs_fixture(filename)}" }
end
context "XML, with path" do
let(:filename) { "service/test/fixtures/profiles/trivial_tw.xml" }
let(:output) do
path = fixture(filename)
Cheetah.run(*command, path, stdout: :capture)
end
include_examples "JSON output structurally matches trivial_tw"
end
context "XML, with file:/// URL" do
let(:filename) { "service/test/fixtures/profiles/trivial_tw.xml" }
let(:output) do
url = "file://" + abs_fixture(filename)
Cheetah.run(*command, url, stdout: :capture)
end
include_examples "JSON output structurally matches trivial_tw"
end
context "ERB, with file:/// URL" do
let(:filename) { "service/test/fixtures/profiles/trivial_tw.xml.erb" }
let(:output) do
url = "file://" + abs_fixture(filename)
Cheetah.run(*command, url, stdout: :capture)
end
include_examples "JSON output structurally matches trivial_tw"
end
# I get a deadlock because two processes want the libstorage lock. why?
xcontext ".../, with file:/// URL" do
let(:filename) { "service/test/fixtures/profiles/profile/" }
it "output matches" do
url = "file://" + abs_fixture(filename)
output = Cheetah.run(*command, url, stdout: :capture)
# this claim is too weak but the test needs to be fixed first
expect(output).to include("Tumbleweed")
end
end
end
end