diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0eb877d6846..e37193966a2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -137,6 +137,24 @@ jobs: path: out/* if: ${{ matrix.primary }} + windows_tests: + needs: basic-checks + name: windows unit tests + runs-on: ubuntu-24.04 + continue-on-error: true + timeout-minutes: 60 + steps: + - uses: actions/checkout@v6 + with: + fetch-depth: 0 + - uses: ./.github/actions/install-nix-action + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + dogfood: ${{ github.event_name == 'workflow_dispatch' && inputs.dogfood || github.event_name != 'workflow_dispatch' }} + - name: Run Windows unit tests + run: | + nix build --file ci/gha/tests/windows.nix unitTests.nix-util-tests -L + installer_test: needs: [tests] strategy: diff --git a/ci/gha/tests/windows.nix b/ci/gha/tests/windows.nix new file mode 100644 index 00000000000..5f13f51dfe3 --- /dev/null +++ b/ci/gha/tests/windows.nix @@ -0,0 +1,30 @@ +{ + nixFlake ? builtins.getFlake ("git+file://" + toString ../../..), + system ? builtins.currentSystem, + pkgs ? nixFlake.inputs.nixpkgs.legacyPackages.${system}, +}: + +let + packages = nixFlake.packages.${system}; + + fixOutput = + test: + test.overrideAttrs (prev: { + nativeBuildInputs = prev.nativeBuildInputs or [ ] ++ [ pkgs.colorized-logs ]; + env.GTEST_COLOR = "no"; + # Wine's console emulation wraps every character in ANSI cursor + # hide/show sequences, making logs unreadable in GitHub Actions. + buildCommand = '' + set -o pipefail + { + ${prev.buildCommand} + } 2>&1 | ansi2txt + ''; + }); +in + +{ + unitTests = { + "nix-util-tests" = fixOutput packages."nix-util-tests-x86_64-w64-mingw32".passthru.tests.run; + }; +} diff --git a/src/libutil-tests/file-descriptor.cc b/src/libutil-tests/file-descriptor.cc index 48816ecb96d..808bb31d8e9 100644 --- a/src/libutil-tests/file-descriptor.cc +++ b/src/libutil-tests/file-descriptor.cc @@ -300,6 +300,9 @@ TEST(BufferedSourceReadLine, BufferExhaustedThenEof) TEST(WriteFull, RespectsAllowInterrupts) { +#ifdef _WIN32 + GTEST_SKIP() << "Broken on Windows"; +#endif Pipe pipe; pipe.create(); diff --git a/src/libutil-tests/file-system-at.cc b/src/libutil-tests/file-system-at.cc index fc387fe8051..5c75fcf86e4 100644 --- a/src/libutil-tests/file-system-at.cc +++ b/src/libutil-tests/file-system-at.cc @@ -13,6 +13,9 @@ namespace nix { TEST(readLinkAt, works) { +#ifdef _WIN32 + GTEST_SKIP() << "Broken on Windows"; +#endif std::filesystem::path tmpDir = nix::createTempDir(); nix::AutoDelete delTmpDir(tmpDir, /*recursive=*/true); @@ -66,6 +69,9 @@ TEST(readLinkAt, works) TEST(openFileEnsureBeneathNoSymlinks, works) { +#ifdef _WIN32 + GTEST_SKIP() << "Broken on Windows"; +#endif std::filesystem::path tmpDir = nix::createTempDir(); nix::AutoDelete delTmpDir(tmpDir, /*recursive=*/true); diff --git a/src/libutil-tests/file-system.cc b/src/libutil-tests/file-system.cc index 5ac0a6289f9..95bfa16b140 100644 --- a/src/libutil-tests/file-system.cc +++ b/src/libutil-tests/file-system.cc @@ -281,11 +281,13 @@ TEST(makeParentCanonical, root) * chmodIfNeeded * --------------------------------------------------------------------------*/ -#ifndef _WIN32 -// Windows doesn't support Unix-style permission bits - lstat always -// returns the same mode regardless of what chmod sets. TEST(chmodIfNeeded, works) { +#ifdef _WIN32 + // Windows doesn't support Unix-style permission bits - lstat always + // returns the same mode regardless of what chmod sets. + GTEST_SKIP() << "Broken on Windows"; +#endif auto [autoClose_, tmpFile] = nix::createTempFile(); auto deleteTmpFile = AutoDelete(tmpFile); @@ -299,7 +301,6 @@ TEST(chmodIfNeeded, works) } } } -#endif TEST(chmodIfNeeded, nonexistent) { diff --git a/src/libutil-tests/source-accessor.cc b/src/libutil-tests/source-accessor.cc index 8f19642a43d..b9da508659b 100644 --- a/src/libutil-tests/source-accessor.cc +++ b/src/libutil-tests/source-accessor.cc @@ -88,6 +88,9 @@ class FSSourceAccessorTest : public ::testing::Test TEST_F(FSSourceAccessorTest, works) { +#ifdef _WIN32 + GTEST_SKIP() << "Broken on Windows"; +#endif { RestoreSink sink(false); sink.dstPath = tmpDir; @@ -156,6 +159,9 @@ TEST_F(FSSourceAccessorTest, RestoreSinkRegularFileAtRoot) TEST_F(FSSourceAccessorTest, RestoreSinkSymlinkAtRoot) { +#ifdef _WIN32 + GTEST_SKIP() << "symlinks have some problems under Wine"; +#endif auto linkPath = tmpDir / "rootlink"; { RestoreSink sink(false); diff --git a/src/libutil/posix-source-accessor.cc b/src/libutil/posix-source-accessor.cc index 79c24197a53..f4b580f5a47 100644 --- a/src/libutil/posix-source-accessor.cc +++ b/src/libutil/posix-source-accessor.cc @@ -182,7 +182,7 @@ std::string PosixSourceAccessor::readLink(const CanonPath & path) { if (auto parent = path.parent()) assertNoSymlinks(*parent); - return nix::readLink(makeAbsPath(path).string()).string(); + return nix::readLink(makeAbsPath(path)).string(); } std::optional PosixSourceAccessor::getPhysicalPath(const CanonPath & path) diff --git a/src/libutil/unix-domain-socket.cc b/src/libutil/unix-domain-socket.cc index 5c8ff944b43..d1ee23df079 100644 --- a/src/libutil/unix-domain-socket.cc +++ b/src/libutil/unix-domain-socket.cc @@ -105,7 +105,12 @@ bindConnectProcHelper(std::string_view operationName, auto && operation, Socket void bind(Socket fd, const std::filesystem::path & path) { - unlink(path.string().c_str()); +#ifdef _WIN32 + _wunlink +#else + unlink +#endif + (path.c_str()); bindConnectProcHelper("bind", ::bind, fd, path.string()); }