266 lines
7.8 KiB
Ruby
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
|