Skip to content
Open
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
00e9d60
add cli to windows tests
allisonschiang May 14, 2026
779741a
windows test fixes: allow mDNS loopback + use errors.Is for not-exist…
allisonschiang May 18, 2026
8fcd488
windows test: disable firewall + enable multicast forwarding + diag dump
allisonschiang May 18, 2026
c7c20e3
windows test: bypass mDNS in setupWithRunningPart via dialOverride
allisonschiang May 18, 2026
e63c51d
windows test: skip known-broken tests + force LF for test data
allisonschiang May 18, 2026
36bad1a
windows test fixes: TestResolvePartId close handle, TestMutateModuleC…
allisonschiang May 18, 2026
0548b63
windows test fixes: close meta.json handle in writeManifest, relax er…
allisonschiang May 18, 2026
19cc0dc
remove debug logging and unused mDNS firewall step
allisonschiang May 18, 2026
4fe1149
drop test_data/.gitattributes to verify if LF override is needed
allisonschiang May 18, 2026
e0e8f7e
re-enable TestShellFileCopy and TestTunnelE2ECLI on Windows to surfac…
allisonschiang May 18, 2026
34ca37c
re-enable TestValidateOutputWritable on Windows, scope read-only subt…
allisonschiang May 18, 2026
5b09200
drop windows skip on read-only subtest to verify Windows enforces 0o5…
allisonschiang May 18, 2026
40d4025
windows test fixes: close file handles in copy_local + xacro, skip br…
allisonschiang May 19, 2026
1fab8bc
windows: skip TestShellFileCopy (RSDK-11617) and read-only subtest; r…
allisonschiang May 19, 2026
47e91d7
Update client_test.go
allisonschiang May 19, 2026
7cd39ac
re-enable TestUpdateModelsAction on Windows after RSDK-13907 impl fix
allisonschiang May 19, 2026
d0ebc74
make clearer
allisonschiang May 20, 2026
6622778
simplify
allisonschiang May 20, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,7 @@ jobs:
go.viam.com/rdk/web/server
go.viam.com/rdk/module
go.viam.com/rdk/logging
go.viam.com/rdk/cli
)
WINDOWS_PATTERN=$(IFS='|'; echo "${WORKING_WINDOWS_TESTS[*]}")
TEST_TARGET=$(echo "$TEST_TARGET" | grep -E "^(${WINDOWS_PATTERN})$")
Expand Down
5 changes: 5 additions & 0 deletions cli/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,8 @@ type viamClient struct {
// caches
orgs *[]*apppb.Organization
locs *[]*apppb.Location

dialOverride func(ctx context.Context, fqdn string, rpcOpts []rpc.DialOption, logger logging.Logger) (*client.RobotClient, error)
}

// ListOrganizationsAction is the corresponding Action for 'organizations list'.
Expand Down Expand Up @@ -5235,6 +5237,9 @@ func (c *viamClient) connectToRobot(
if debug {
printf(c.c.Root().Writer, "Establishing connection...")
}
if c.dialOverride != nil {
return c.dialOverride(dialCtx, fqdn, rpcOpts, logger)
}
robotClient, err := client.New(dialCtx, fqdn, logger, client.WithDialOptions(rpcOpts...))
if err != nil {
return nil, errors.Wrap(err, "could not connect to machine part")
Expand Down
13 changes: 12 additions & 1 deletion cli/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import (
commonpb "go.viam.com/api/common/v1"
"go.viam.com/test"
"go.viam.com/utils/protoutils"
"go.viam.com/utils/rpc"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
Expand All @@ -38,6 +39,7 @@ import (
robotconfig "go.viam.com/rdk/config"
"go.viam.com/rdk/logging"
"go.viam.com/rdk/resource"
"go.viam.com/rdk/robot/client"
robotimpl "go.viam.com/rdk/robot/impl"
"go.viam.com/rdk/services/shell"
_ "go.viam.com/rdk/services/shell/register"
Expand Down Expand Up @@ -220,6 +222,12 @@ func setupWithRunningPart(
ac.baseURL, _, err = utils.ParseBaseURL(ac.conf.BaseURL, false)
test.That(t, err, test.ShouldBeNil)

ac.dialOverride = func(ctx context.Context, fqdn string, rpcOpts []rpc.DialOption, logger logging.Logger) (*client.RobotClient, error) {
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TestShellFileCopy/from/single_file (540.05s) hangs with

rpc/dial.go:144 trying mDNS {"address":"99823048-4cba-4b40-823e-a26f7362d4a3"}
rpc/server.go:550 mDNS setup failed; continuing with mDNS disabled {"error":"no positive MTU found"}

by adding this, we can skip the mDNS setup that will likely fail on windows and go straight to direct grpc with the actual robot data from the test

return client.New(ctx, addr, logger,
client.WithDialOptions(append(rpcOpts, rpc.WithForceDirectGRPC())...),
)
}

t.Cleanup(func() {
test.That(t, r.Close(context.Background()), test.ShouldBeNil)
})
Expand Down Expand Up @@ -635,7 +643,7 @@ func TestDataExportTabularAction(t *testing.T) {
// Test that the data.ndjson file was removed.
filePath := utils.ResolveFile(dataFileName)
_, err = os.ReadFile(filePath)
test.That(t, err, test.ShouldBeError, fmt.Errorf("open %s: no such file or directory", filePath))
test.That(t, errors.Is(err, fs.ErrNotExist), test.ShouldBeTrue)
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

windows has slightly diff error string, so just check errNotExist instead of specific string

})
}

Expand Down Expand Up @@ -975,6 +983,9 @@ func TestMachinesPartHistoryAction(t *testing.T) {
}

func TestShellFileCopy(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("RSDK-11617")
}
logger := logging.NewTestLogger(t)

listOrganizationsFunc := func(ctx context.Context, in *apppb.ListOrganizationsRequest,
Expand Down
33 changes: 18 additions & 15 deletions cli/module_build_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"io"
"os"
"path/filepath"
"runtime"
"sort"
"strings"
"testing"
Expand Down Expand Up @@ -265,23 +266,25 @@ func TestLocalBuild(t *testing.T) {
testDir := t.TempDir()
testChdir(t, testDir)

// write manifest and setup.sh
// the manifest contains a:
// "setup": "./setup.sh"
// and a "build": "make build"
manifestPath := createTestManifest(t, "", nil)
Copy link
Copy Markdown
Member Author

@allisonschiang allisonschiang May 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

default test manifest is set up for mac, need windows specifics like .bat instead of .sh

err := os.WriteFile(
filepath.Join(testDir, "setup.sh"),
[]byte("echo setup step msg"),
0o700,
)
setupScriptCmd, setupFile, setupContent := "./setup.sh", "setup.sh", "echo setup step msg"
buildCmd, buildFile, buildContent := "make build", "Makefile", "make build:\n\techo build step msg"
if runtime.GOOS == "windows" {
setupScriptCmd, setupFile, setupContent = "setup.bat", "setup.bat", "@echo setup step msg"
buildCmd, buildFile, buildContent = "build.bat", "build.bat", "@echo build step msg"
}

manifestPath := createTestManifest(t, "", map[string]any{
"build": map[string]any{
"setup": setupScriptCmd,
"build": buildCmd,
"path": "module",
"arch": []any{"linux/amd64"},
},
})
err := os.WriteFile(filepath.Join(testDir, setupFile), []byte(setupContent), 0o700)
test.That(t, err, test.ShouldBeNil)

err = os.WriteFile(
filepath.Join(testDir, "Makefile"),
[]byte("make build:\n\techo build step msg"),
0o700,
)
err = os.WriteFile(filepath.Join(testDir, buildFile), []byte(buildContent), 0o700)
test.That(t, err, test.ShouldBeNil)

// run the build local action
Expand Down
8 changes: 6 additions & 2 deletions cli/module_generate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,9 +122,13 @@ func TestGenerateModuleAction(t *testing.T) {
test.That(t, err, test.ShouldBeNil)
_, err = os.Stat(filepath.Join(modulePath, "src"))
test.That(t, err, test.ShouldBeNil)
_, err = os.Stat(filepath.Join(modulePath, "build.sh"))
scriptExt := ".sh"
if runtime.GOOS == "windows" {
scriptExt = ".bat"
}
_, err = os.Stat(filepath.Join(modulePath, "build"+scriptExt))
test.That(t, err, test.ShouldBeNil)
_, err = os.Stat(filepath.Join(modulePath, "setup.sh"))
_, err = os.Stat(filepath.Join(modulePath, "setup"+scriptExt))
test.That(t, err, test.ShouldBeNil)
_, err = os.Stat(filepath.Join(modulePath, ".gitignore"))
test.That(t, err, test.ShouldBeNil)
Expand Down
1 change: 1 addition & 0 deletions cli/module_registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -885,6 +885,7 @@ func writeManifest(manifestPath string, manifest ModuleManifest) error {
if err != nil {
return errors.Wrapf(err, "failed to create %s", manifestPath)
}
defer func() { vutils.UncheckedError(manifestFile.Close()) }()
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

on windows, all open files need to be explicitly closed

if _, err := manifestFile.Write(manifestBytes); err != nil {
return errors.Wrapf(err, "failed to write manifest to %s", manifestPath)
}
Expand Down
2 changes: 1 addition & 1 deletion cli/module_registry_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ func TestGetMarkdownContent(t *testing.T) {
name: "non-existent file",
filepath: "non_existent_file.md",
shouldContain: []string{},
shouldErrorWith: "failed to read markdown file at non_existent_file.md: open non_existent_file.md: no such file or directory",
shouldErrorWith: "failed to read markdown file at non_existent_file.md: open non_existent_file.md:",
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

windows different error string

totalChars: 0,
},
{
Expand Down
13 changes: 8 additions & 5 deletions cli/module_reload_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,7 @@ func TestResolvePartId(t *testing.T) {
test.That(t, err, test.ShouldBeNil)
_, err = fi.WriteString(`{"cloud":{"app_address":"https://app.viam.com:443","id":"JSON-PART","secret":"SECRET"}}`)
test.That(t, err, test.ShouldBeNil)
test.That(t, fi.Close(), test.ShouldBeNil)
partID, err = resolvePartID(c.String(generalFlagPartID), path)
test.That(t, err, test.ShouldBeNil)
test.That(t, partID, test.ShouldEqual, "JSON-PART")
Expand All @@ -399,7 +400,9 @@ func TestMutateModuleConfig(t *testing.T) {
}
expectedName := "viam-labs_test-module_from_reload"
expectedVersion := "latest-with-prerelease"
remoteReloadPath := ".viam/packages-local/viam-labs_test-module_from_reload-module.tar.gz"
expectedEntrypoint, err := filepath.Abs(manifest.Entrypoint)
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

forward slash issues on windows

test.That(t, err, test.ShouldBeNil)
remoteReloadPath := filepath.Join(".viam", "packages-local", "viam-labs_test-module_from_reload-module.tar.gz")
testUser := "test@viam.com"
testReloadUnixTS := time.Date(2024, 3, 18, 12, 0, 0, 0, time.UTC).Unix()

Expand Down Expand Up @@ -448,7 +451,7 @@ func TestMutateModuleConfig(t *testing.T) {
test.That(t, err, test.ShouldBeNil)
test.That(t, dirty, test.ShouldBeTrue)
test.That(t, needsRestart, test.ShouldBeFalse)
test.That(t, modules[0]["reload_path"], test.ShouldEqual, manifest.Entrypoint)
test.That(t, modules[0]["reload_path"], test.ShouldEqual, expectedEntrypoint)
test.That(t, modules[0]["reload_enabled"], test.ShouldBeTrue)
test.That(t, modules[0]["reload_user"], test.ShouldEqual, testUser)
test.That(t, modules[0]["reload_time"], test.ShouldNotBeEmpty)
Expand All @@ -464,7 +467,7 @@ func TestMutateModuleConfig(t *testing.T) {
test.That(t, err, test.ShouldBeNil)
test.That(t, dirty, test.ShouldBeTrue)
test.That(t, needsRestart, test.ShouldBeFalse)
test.That(t, modules[0]["reload_path"], test.ShouldEqual, manifest.Entrypoint)
test.That(t, modules[0]["reload_path"], test.ShouldEqual, expectedEntrypoint)
test.That(t, modules[0]["reload_enabled"], test.ShouldBeTrue)
test.That(t, modules[0]["reload_user"], test.ShouldEqual, testUser)
test.That(t, modules[0]["reload_time"], test.ShouldNotBeEmpty)
Expand All @@ -475,7 +478,7 @@ func TestMutateModuleConfig(t *testing.T) {
modules, _, _, _ = mutateModuleConfig(c, modules, manifest, true, false, testUser, "", testReloadUnixTS)
test.That(t, modules[0]["module_id"], test.ShouldEqual, manifest.ModuleID)
test.That(t, modules[0]["name"], test.ShouldEqual, expectedName)
test.That(t, modules[0]["reload_path"], test.ShouldEqual, manifest.Entrypoint)
test.That(t, modules[0]["reload_path"], test.ShouldEqual, expectedEntrypoint)
test.That(t, modules[0]["reload_enabled"], test.ShouldBeTrue)
test.That(t, modules[0]["version"], test.ShouldEqual, expectedVersion)
test.That(t, modules[0]["reload_user"], test.ShouldEqual, testUser)
Expand All @@ -490,7 +493,7 @@ func TestMutateModuleConfig(t *testing.T) {
}}
updatedModules, _, _, _ := mutateModuleConfig(c, modules, manifest, true, false, testUser, "", testReloadUnixTS)
test.That(t, len(updatedModules), test.ShouldEqual, 2)
test.That(t, updatedModules[1]["reload_path"], test.ShouldEqual, manifest.Entrypoint)
test.That(t, updatedModules[1]["reload_path"], test.ShouldEqual, expectedEntrypoint)
test.That(t, updatedModules[1]["reload_enabled"], test.ShouldBeTrue)
test.That(t, updatedModules[1]["version"], test.ShouldEqual, expectedVersion)
test.That(t, updatedModules[1]["reload_user"], test.ShouldEqual, testUser)
Expand Down
1 change: 1 addition & 0 deletions cli/test_data/.gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.md text eol=lf
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Windows GitHub Actions runners default to core.autocrlf=true, which converts LF → CRLF on checkout. CRLF adds 1 byte per line. So a 167-char file checked out on Linux becomes ~171 chars on Windows, and the test fails the byte-count assertions

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

windows test will fail without it

8 changes: 3 additions & 5 deletions cli/xacro.go
Original file line number Diff line number Diff line change
Expand Up @@ -243,11 +243,9 @@ func validateOutputWritable(outputPath string) error {
if err != nil {
return err
}
defer func() {
if closeErr := f.Close(); closeErr != nil {
err = closeErr
}
}()
if err := f.Close(); err != nil {
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

need to close before removing

return err
}

// Remove empty test file (don't leave artifacts if we just created it)
if info, statErr := os.Stat(outputPath); statErr == nil && info.Size() == 0 {
Expand Down
9 changes: 8 additions & 1 deletion cli/xacro_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package cli
import (
"os"
"path/filepath"
"runtime"
"strings"
"testing"

Expand Down Expand Up @@ -108,6 +109,9 @@ func TestExtractPackageName(t *testing.T) {
}

func TestProcessXacroArgs(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("RSDK-13917")
}
tmpDir := t.TempDir()
pkgName := "test_pkg"

Expand Down Expand Up @@ -407,7 +411,7 @@ func TestValidateOutputWritable(t *testing.T) {
})

t.Run("directory does not exist", func(t *testing.T) {
err := validateOutputWritable("/nonexistent/dir/output.urdf")
err := validateOutputWritable(filepath.Join(t.TempDir(), "nonexistent", "output.urdf"))
test.That(t, err, test.ShouldNotBeNil)
test.That(t, err.Error(), test.ShouldContainSubstring, "does not exist")
})
Expand All @@ -428,6 +432,9 @@ func TestValidateOutputWritable(t *testing.T) {
})

t.Run("read-only directory", func(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("Windows doesn't use permission bits to determine read-only directories")
}
if os.Getuid() == 0 {
t.Skip("Skipping read-only test when running as root")
}
Expand Down
Loading