agama/service/test/integration/profile_itest.rb
Martin Vidner d787888753 agama config generate: handle AutoYaST profiles specified as paths
by converting to file:///absolute_path
2025-06-09 11:43:07 +02:00

272 lines
7.7 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 "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|
context "with #{filename} as path" do
it "output matches" do
cmd = [*command, fixture(filename)]
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 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
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/agama-lib/share/examples/profile_tw_minimal.json", \
"", \
"is valid"
end
context "valid profile with space in path" do
include_examples \
"accepts input in 3 ways", \
"rust/agama-lib/share/examples space/profile_tw_minimal.json", \
"", \
"is valid"
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/agama-lib/share/examples%20percent/profile_tw_minimal.json", \
"", \
"is valid"
end
context "invalid profile" do
include_examples \
"accepts input in 3 ways", \
"rust/agama-lib/share/examples/profile_tw_invalid.json", \
"", \
"* Additional properties are not allowed ('ID' was unexpected). /product"
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/agama-lib/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/agama-lib/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)
expect(stderr).to include("profile is valid")
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)
# NOTE: 3 space indent here
expected = <<~JSON
{
"product": {
"uh": "oh"
}
}
JSON
expect(stdout).to eq(expected)
expect(stderr).to include("profile is not valid")
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"] }
let(:output_match) do
json = <<~JSON
{
"software": {
"patterns": [
"base"
],
"packages": []
},
"product": {
"id": "Tumbleweed"
}
}
JSON
json
end
# 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" }
it "output matches" do
path = fixture(filename)
output = Cheetah.run(*command, path, stdout: :capture)
expect(output).to include(output_match)
end
end
context "XML, with file:/// URL" do
let(:filename) { "service/test/fixtures/profiles/trivial_tw.xml" }
it "output matches" do
url = "file://" + abs_fixture(filename)
output = Cheetah.run(*command, url, stdout: :capture)
expect(output).to include(output_match)
end
end
context "ERB, with file:/// URL" do
let(:filename) { "service/test/fixtures/profiles/trivial_tw.xml.erb" }
it "output matches" do
url = "file://" + abs_fixture(filename)
output = Cheetah.run(*command, url, stdout: :capture)
expect(output).to include(output_match)
end
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