diff --git a/.github/workflows/test_nixos_minimal.yml b/.github/workflows/test_nixos_minimal.yml index 45e55ae14..9d84be8e8 100644 --- a/.github/workflows/test_nixos_minimal.yml +++ b/.github/workflows/test_nixos_minimal.yml @@ -17,6 +17,15 @@ jobs: runs-on: ubuntu-latest strategy: fail-fast: false + matrix: + test: + - name: hello + disk_size: 6144 + - name: go + disk_size: 8192 + + name: Test ${{ matrix.test.name }} + timeout-minutes: 60 steps: # In the subsequent tests, a relatively large disk (4GB) will be created to install AsterNixOS. # Standard GitHub runners may encounter "insufficient disk space" errors. @@ -32,12 +41,11 @@ jobs: remove_haskell: true remove_tool_cache: true - uses: actions/checkout@v4 - - name: Run the hello test on AsterNixOS - timeout-minutes: 30 + - name: Run the ${{ matrix.test.name }} test on AsterNixOS uses: addnab/docker-run-action@v3 with: image: asterinas/asterinas:0.17.0-20260114 options: --privileged -v /dev:/dev -v ${{ github.workspace }}:/root/asterinas run: | - make nixos NIXOS_TEST_SUITE=hello NIXOS_DISK_SIZE_IN_MB=6144 - make run_nixos NIXOS_TEST_SUITE=hello \ No newline at end of file + make nixos NIXOS_TEST_SUITE=${{ matrix.test.name }} NIXOS_DISK_SIZE_IN_MB=${{ matrix.test.disk_size }} + make run_nixos NIXOS_TEST_SUITE=${{ matrix.test.name }} diff --git a/test/nixos/Cargo.lock b/test/nixos/Cargo.lock index 4e1a92452..735a4ce33 100644 --- a/test/nixos/Cargo.lock +++ b/test/nixos/Cargo.lock @@ -245,6 +245,13 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "test-go" +version = "0.1.0" +dependencies = [ + "nixos-test-framework", +] + [[package]] name = "test-hello" version = "0.1.0" diff --git a/test/nixos/common/framework/src/session.rs b/test/nixos/common/framework/src/session.rs index 04f4a4448..45201b7b6 100644 --- a/test/nixos/common/framework/src/session.rs +++ b/test/nixos/common/framework/src/session.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MPL-2.0 -use rexpect::session::PtySession; +use rexpect::{reader::Regex, session::PtySession}; use super::Error; @@ -153,9 +153,9 @@ impl Session { Ok(()) } - /// Executes a command and verifies its output contains expected text. + /// Executes a command and verifies its output matches expected regex. /// - /// This method runs the command and checks that the specified string appears + /// This method runs the command and checks that the specified regex appears /// in the output. This is useful for validating command results. /// /// Returns an error if: @@ -178,6 +178,9 @@ impl Session { /// // Verify system information /// nixos_shell.run_cmd_and_expect("cat /etc/os-release", "NixOS")?; /// + /// // Verify output matches regex + /// nixos_shell.run_cmd_and_expect_regex("echo 'Hello, World!'", "(?m)^H.*!$")?; + /// /// Ok(()) /// } /// ``` @@ -191,7 +194,7 @@ impl Session { Ok(unread) => { let cleaned_unread = String::from_utf8_lossy(&strip_ansi_escapes::strip(&unread)).to_string(); - if !cleaned_unread.contains(expected) { + if !Regex::new(expected)?.is_match(&cleaned_unread) { println!("=== Unexpected Output ==="); println!("Expected: {}", expected); println!("Output before prompt:\n{}", cleaned_unread); diff --git a/test/nixos/tests/go/Cargo.toml b/test/nixos/tests/go/Cargo.toml new file mode 100644 index 000000000..635ea1be6 --- /dev/null +++ b/test/nixos/tests/go/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "test-go" +version.workspace = true +repository.workspace = true +license.workspace = true +edition.workspace = true + +[dependencies] +nixos-test-framework.workspace = true diff --git a/test/nixos/tests/go/extra_config.nix b/test/nixos/tests/go/extra_config.nix new file mode 100644 index 000000000..0454f5cb5 --- /dev/null +++ b/test/nixos/tests/go/extra_config.nix @@ -0,0 +1,5 @@ +{ config, lib, pkgs, ... }: + +{ + environment.systemPackages = with pkgs; [ go ]; +} diff --git a/test/nixos/tests/go/src/main.rs b/test/nixos/tests/go/src/main.rs new file mode 100644 index 000000000..9caaf34c9 --- /dev/null +++ b/test/nixos/tests/go/src/main.rs @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: MPL-2.0 + +//! The test suite for Go standard library tests on Asterinas NixOS. +//! +//! # Document maintenance +//! +//! An application's test suite and its "Verified Usage" section in Asterinas Book +//! should always be kept in sync. +//! So whenever you modify the test suite, +//! review the documentation and see if should be updated accordingly. + +use nixos_test_framework::*; + +nixos_test_main!(); + +#[nixos_test] +fn go(nixos_shell: &mut Session) -> Result<(), Error> { + let testcases = std::fs::read_to_string("src/testcases.txt")?; + for line in testcases.lines() { + let line = line.trim(); + if line.is_empty() || line.starts_with("#") { + continue; + } + + let cmd = format!("go test -short {}", line); + nixos_shell.run_cmd_and_expect(&cmd, r"(?m)^(ok|\?) .*$")?; + } + + Ok(()) +} diff --git a/test/nixos/tests/go/src/testcases.txt b/test/nixos/tests/go/src/testcases.txt new file mode 100644 index 000000000..84b53403e --- /dev/null +++ b/test/nixos/tests/go/src/testcases.txt @@ -0,0 +1,350 @@ +# This test list can be generated by the following command: +# go list std +# +# FIXME: Many of the tests below can pass when run individually, but when enabled, +# they may cause CI failures, primarily due to ext2 issues or runtime errors. + +# archive/tar +# archive/zip +bufio +bytes +cmp +# compress/bzip2 +# compress/flate +# compress/gzip +# compress/lzw +# compress/zlib +container/heap +container/list +container/ring +context +# crypto +# crypto/aes +# crypto/cipher +# crypto/des +# crypto/dsa +# crypto/ecdh +# crypto/ecdsa +# crypto/ed25519 +# crypto/elliptic +# crypto/fips140 +# crypto/hkdf +# crypto/hmac +# crypto/internal/boring +# crypto/internal/boring/bbig +# crypto/internal/boring/bcache +# crypto/internal/boring/sig +# crypto/internal/cryptotest +# crypto/internal/entropy +# crypto/internal/fips140 +# crypto/internal/fips140/aes +# crypto/internal/fips140/aes/gcm +# crypto/internal/fips140/alias +# crypto/internal/fips140/bigmod +# crypto/internal/fips140/check +# crypto/internal/fips140/check/checktest +# crypto/internal/fips140/drbg +# crypto/internal/fips140/ecdh +# crypto/internal/fips140/ecdsa +# crypto/internal/fips140/ed25519 +# crypto/internal/fips140/edwards25519 +# crypto/internal/fips140/edwards25519/field +# crypto/internal/fips140/hkdf +# crypto/internal/fips140/hmac +# crypto/internal/fips140/mlkem +# crypto/internal/fips140/nistec +# crypto/internal/fips140/nistec/fiat +# crypto/internal/fips140/pbkdf2 +# crypto/internal/fips140/rsa +# crypto/internal/fips140/sha256 +# crypto/internal/fips140/sha3 +# crypto/internal/fips140/sha512 +# crypto/internal/fips140/ssh +# crypto/internal/fips140/subtle +# crypto/internal/fips140/tls12 +# crypto/internal/fips140/tls13 +# crypto/internal/fips140deps +# crypto/internal/fips140deps/byteorder +# crypto/internal/fips140deps/cpu +# crypto/internal/fips140deps/godebug +# crypto/internal/fips140hash +# crypto/internal/fips140only +# crypto/internal/fips140test +# crypto/internal/hpke +# crypto/internal/impl +# crypto/internal/randutil +# crypto/internal/sysrand +# crypto/internal/sysrand/internal/seccomp +# crypto/md5 +# crypto/mlkem +# crypto/pbkdf2 +# crypto/rand +# crypto/rc4 +# crypto/rsa +# crypto/sha1 +# crypto/sha256 +# crypto/sha3 +# crypto/sha512 +# crypto/subtle +# crypto/tls +# crypto/tls/internal/fips140tls +# crypto/x509 +# crypto/x509/pkix +# database/sql +# database/sql/driver +# debug/buildinfo +# debug/dwarf +# debug/elf +# debug/gosym +# debug/macho +# debug/pe +# debug/plan9obj +# embed +# embed/internal/embedtest +# encoding +# encoding/ascii85 +# encoding/asn1 +# encoding/base32 +# encoding/base64 +# encoding/binary +# encoding/csv +# encoding/gob -skip='TestCountDecodeMallocs' +# encoding/hex +# encoding/json +# encoding/pem +# encoding/xml +errors +expvar +flag +fmt +# go/ast +# go/ast/internal/tests +go/build +go/build/constraint +# go/constant +# go/doc +# go/doc/comment +# go/format +# go/importer +# go/internal/gccgoimporter +# go/internal/gcimporter +# go/internal/srcimporter +# go/parser +# go/printer +# go/scanner +# go/token +# go/types +# go/version +# hash +# hash/adler32 +# hash/crc32 +# hash/crc64 +# hash/fnv +# hash/maphash +# html +# html/template +# image +# image/color +# image/color/palette +# image/draw +# image/gif +# image/internal/imageutil +# image/jpeg +# image/png +# index/suffixarray +# internal/abi +# internal/asan +# internal/bisect +# internal/buildcfg +# internal/bytealg +# internal/byteorder +# internal/cfg +# internal/chacha8rand +# internal/copyright +# internal/coverage +# internal/coverage/calloc +# internal/coverage/cfile +# internal/coverage/cformat +# internal/coverage/cmerge +# internal/coverage/decodecounter +# internal/coverage/decodemeta +# internal/coverage/encodecounter +# internal/coverage/encodemeta +# internal/coverage/pods +# internal/coverage/rtcov +# internal/coverage/slicereader +# internal/coverage/slicewriter +# internal/coverage/stringtab +# internal/coverage/test +# internal/coverage/uleb128 +# internal/cpu +# internal/dag +# internal/diff +# internal/exportdata +# internal/filepathlite +# internal/fmtsort +# internal/fuzz +# internal/goarch +# internal/godebug +# internal/godebugs +# internal/goexperiment +# internal/goos +# internal/goroot +# internal/gover +# internal/goversion +# internal/itoa +# internal/lazyregexp +# internal/lazytemplate +# internal/msan +# internal/nettrace +# internal/obscuretestdata +# internal/oserror +# internal/pkgbits +# internal/platform +# internal/poll +# internal/profile +# internal/profilerecord +# internal/race +# internal/reflectlite +# internal/runtime/atomic +# internal/runtime/exithook +# internal/runtime/maps +# internal/runtime/math +# internal/runtime/sys +# internal/runtime/syscall +# internal/saferio +# internal/singleflight +# internal/stringslite +# internal/sync +# internal/synctest +# internal/syscall/execenv +# internal/syscall/unix +# internal/sysinfo +# internal/syslist +# internal/testenv +# internal/testlog +# internal/testpty +# internal/trace +# internal/trace/event +# internal/trace/event/go122 +# internal/trace/internal/oldtrace +# internal/trace/internal/testgen/go122 +# internal/trace/raw +# internal/trace/testtrace +# internal/trace/traceviewer +# internal/trace/traceviewer/format +# internal/trace/version +# internal/txtar +# internal/types/errors +# internal/unsafeheader +# internal/xcoff +# internal/zstd +io +io/fs +io/ioutil +iter +# log +# log/internal +# log/slog +# log/slog/internal +# log/slog/internal/benchmarks +# log/slog/internal/buffer +# log/slog/internal/slogtest +# log/syslog +maps +# math +# math/big +# math/bits +# math/cmplx +# math/rand +# math/rand/v2 +# mime +# mime/multipart +# mime/quotedprintable +# net +net/http -skip='TestServerKeepAliveAfterWriteError|TestDisableKeepAliveUpgrade|TestSOCKS5Proxy|TestTransportProxy|TestOmitHTTP2' +net/http/cgi +net/http/cookiejar +net/http/fcgi +net/http/httptest +net/http/httptrace +net/http/httputil +# net/http/internal +# net/http/internal/ascii +# net/http/internal/testcert +net/http/pprof +# net/internal/cgotest +# net/internal/socktest +net/mail +net/netip +net/rpc +net/rpc/jsonrpc +net/smtp +net/textproto +net/url +os -skip='TestLargeCopyViaNetwork|TestSpliceFile|TestGetPollFDAndNetwork|TestSendFile|TestRootConsistencyOpen/symlink_slash|TestRootConsistencyCreate/symlink_slash|TestRootConsistencyRemove/unreadable_directory|TestRootConsistencyStat/symlink_slash|TestRootRaceRenameDir|TestNonpollableDeadline|TestSymlinkWithTrailingSlash|TestRemoveAll' +# os/exec -skip='TestExtraFiles|TestFindExecutableVsNoexec' +# os/exec/internal/fdtest +os/signal +os/user +path +path/filepath -skip='TestWalkSymlinkRoot' +plugin +# reflect +# reflect/internal/example1 +# reflect/internal/example2 +# regexp +# regexp/syntax +runtime -skip='TestBreakpoint|TestAbort|TestDebugCall|TestNonblockingPipe|TestMincoreErrorSign' +runtime/coverage +# runtime/debug -skip='TestPanicOnFault' +# runtime/internal/startlinetest +# runtime/internal/wasitest +runtime/metrics +runtime/pprof -skip='TestCPUProfile|TestMathBigDivide|TestMorestack|TestLabelRace|TestLabelSystemstack|TestTimeVDSO' +runtime/race +# runtime/race/internal/amd64v1 +runtime/trace +slices +sort +strconv +strings +structs +# sync +# sync/atomic +syscall -skip='TestSCMCredentials|TestUseCgroupFD|TestFchmodat|TestSetuidEtc|TestPrlimitOtherProcess|TestPrlimitFileLimit|TestExecPtrace|TestFcntlFlock|TestPassFD' +# testing +# testing/fstest +# testing/internal/testdeps +# testing/iotest +# testing/quick +# testing/slogtest +# text/scanner +# text/tabwriter +# text/template +# text/template/parse +time +time/tzdata +unicode +unicode/utf16 +unicode/utf8 +unique +unsafe +# vendor/golang.org/x/crypto/chacha20 +# vendor/golang.org/x/crypto/chacha20poly1305 +# vendor/golang.org/x/crypto/cryptobyte +# vendor/golang.org/x/crypto/cryptobyte/asn1 +# vendor/golang.org/x/crypto/internal/alias +# vendor/golang.org/x/crypto/internal/poly1305 +# vendor/golang.org/x/net/dns/dnsmessage +# vendor/golang.org/x/net/http/httpguts +# vendor/golang.org/x/net/http/httpproxy +# vendor/golang.org/x/net/http2/hpack +# vendor/golang.org/x/net/idna +# vendor/golang.org/x/net/nettest +# vendor/golang.org/x/sys/cpu +# vendor/golang.org/x/text/secure/bidirule +# vendor/golang.org/x/text/transform +# vendor/golang.org/x/text/unicode/bidi +# vendor/golang.org/x/text/unicode/norm +weak