summaryrefslogtreecommitdiffhomepage
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/e2e/integration_test.go15
-rw-r--r--test/packetimpact/testbench/BUILD1
-rw-r--r--test/packetimpact/testbench/layers.go13
-rw-r--r--test/packetimpact/testbench/layers_test.go112
-rw-r--r--test/packetimpact/tests/BUILD18
-rw-r--r--test/packetimpact/tests/defs.bzl10
-rw-r--r--test/packetimpact/tests/tcp_retransmits_test.go84
-rw-r--r--test/syscalls/linux/BUILD6
-rw-r--r--test/syscalls/linux/fpsig_fork.cc32
-rw-r--r--test/syscalls/linux/itimer.cc21
-rw-r--r--test/syscalls/linux/socket.cc9
-rw-r--r--test/syscalls/linux/socket_ip_tcp_generic.cc45
-rw-r--r--test/syscalls/linux/symlink.cc25
-rw-r--r--test/syscalls/linux/tcp_socket.cc185
-rw-r--r--test/syscalls/linux/udp_socket_test_cases.cc48
-rw-r--r--test/syscalls/linux/utimes.cc33
16 files changed, 616 insertions, 41 deletions
diff --git a/test/e2e/integration_test.go b/test/e2e/integration_test.go
index 404e37689..ff856883a 100644
--- a/test/e2e/integration_test.go
+++ b/test/e2e/integration_test.go
@@ -361,6 +361,21 @@ func TestTmpFile(t *testing.T) {
}
}
+// TestHostOverlayfsCopyUp tests that the --overlayfs-stale-read option causes
+// runsc to hide the incoherence of FDs opened before and after overlayfs
+// copy-up on the host.
+func TestHostOverlayfsCopyUp(t *testing.T) {
+ d := dockerutil.MakeDocker(t)
+ defer d.CleanUp()
+
+ if _, err := d.Run(dockerutil.RunOpts{
+ Image: "hostoverlaytest",
+ WorkDir: "/root",
+ }, "./test"); err != nil {
+ t.Fatalf("docker run failed: %v", err)
+ }
+}
+
func TestMain(m *testing.M) {
dockerutil.EnsureSupportedDockerVersion()
flag.Parse()
diff --git a/test/packetimpact/testbench/BUILD b/test/packetimpact/testbench/BUILD
index fed51006f..682933067 100644
--- a/test/packetimpact/testbench/BUILD
+++ b/test/packetimpact/testbench/BUILD
@@ -39,6 +39,7 @@ go_test(
library = ":testbench",
deps = [
"//pkg/tcpip",
+ "//pkg/tcpip/header",
"@com_github_mohae_deepcopy//:go_default_library",
],
)
diff --git a/test/packetimpact/testbench/layers.go b/test/packetimpact/testbench/layers.go
index 49370377d..1b0e5b8fc 100644
--- a/test/packetimpact/testbench/layers.go
+++ b/test/packetimpact/testbench/layers.go
@@ -689,6 +689,7 @@ type TCP struct {
WindowSize *uint16
Checksum *uint16
UrgentPointer *uint16
+ Options []byte
}
func (l *TCP) String() string {
@@ -697,7 +698,7 @@ func (l *TCP) String() string {
// ToBytes implements Layer.ToBytes.
func (l *TCP) ToBytes() ([]byte, error) {
- b := make([]byte, header.TCPMinimumSize)
+ b := make([]byte, l.length())
h := header.TCP(b)
if l.SrcPort != nil {
h.SetSourcePort(*l.SrcPort)
@@ -727,6 +728,8 @@ func (l *TCP) ToBytes() ([]byte, error) {
if l.UrgentPointer != nil {
h.SetUrgentPoiner(*l.UrgentPointer)
}
+ copy(b[header.TCPMinimumSize:], l.Options)
+ header.AddTCPOptionPadding(b[header.TCPMinimumSize:], len(l.Options))
if l.Checksum != nil {
h.SetChecksum(*l.Checksum)
return h, nil
@@ -811,6 +814,7 @@ func parseTCP(b []byte) (Layer, layerParser) {
WindowSize: Uint16(h.WindowSize()),
Checksum: Uint16(h.Checksum()),
UrgentPointer: Uint16(h.UrgentPointer()),
+ Options: b[header.TCPMinimumSize:h.DataOffset()],
}
return &tcp, parsePayload
}
@@ -821,7 +825,12 @@ func (l *TCP) match(other Layer) bool {
func (l *TCP) length() int {
if l.DataOffset == nil {
- return header.TCPMinimumSize
+ // TCP header including the options must end on a 32-bit
+ // boundary; the user could potentially give us a slice
+ // whose length is not a multiple of 4 bytes, so we have
+ // to do the alignment here.
+ optlen := (len(l.Options) + 3) & ^3
+ return header.TCPMinimumSize + optlen
}
return int(*l.DataOffset)
}
diff --git a/test/packetimpact/testbench/layers_test.go b/test/packetimpact/testbench/layers_test.go
index 96f72de5b..c7f00e70d 100644
--- a/test/packetimpact/testbench/layers_test.go
+++ b/test/packetimpact/testbench/layers_test.go
@@ -15,10 +15,13 @@
package testbench
import (
+ "bytes"
+ "net"
"testing"
"github.com/mohae/deepcopy"
"gvisor.dev/gvisor/pkg/tcpip"
+ "gvisor.dev/gvisor/pkg/tcpip/header"
)
func TestLayerMatch(t *testing.T) {
@@ -393,3 +396,112 @@ func TestLayersDiff(t *testing.T) {
}
}
}
+
+func TestTCPOptions(t *testing.T) {
+ for _, tt := range []struct {
+ description string
+ wantBytes []byte
+ wantLayers Layers
+ }{
+ {
+ description: "without payload",
+ wantBytes: []byte{
+ // IPv4 Header
+ 0x45, 0x00, 0x00, 0x2c, 0x00, 0x01, 0x00, 0x00, 0x40, 0x06,
+ 0xf9, 0x77, 0xc0, 0xa8, 0x00, 0x02, 0xc0, 0xa8, 0x00, 0x01,
+ // TCP Header
+ 0x30, 0x39, 0xd4, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x60, 0x02, 0x20, 0x00, 0xf5, 0x1c, 0x00, 0x00,
+ // WindowScale Option
+ 0x03, 0x03, 0x02,
+ // NOP Option
+ 0x00,
+ },
+ wantLayers: []Layer{
+ &IPv4{
+ IHL: Uint8(20),
+ TOS: Uint8(0),
+ TotalLength: Uint16(44),
+ ID: Uint16(1),
+ Flags: Uint8(0),
+ FragmentOffset: Uint16(0),
+ TTL: Uint8(64),
+ Protocol: Uint8(uint8(header.TCPProtocolNumber)),
+ Checksum: Uint16(0xf977),
+ SrcAddr: Address(tcpip.Address(net.ParseIP("192.168.0.2").To4())),
+ DstAddr: Address(tcpip.Address(net.ParseIP("192.168.0.1").To4())),
+ },
+ &TCP{
+ SrcPort: Uint16(12345),
+ DstPort: Uint16(54321),
+ SeqNum: Uint32(0),
+ AckNum: Uint32(0),
+ Flags: Uint8(header.TCPFlagSyn),
+ WindowSize: Uint16(8192),
+ Checksum: Uint16(0xf51c),
+ UrgentPointer: Uint16(0),
+ Options: []byte{3, 3, 2, 0},
+ },
+ &Payload{Bytes: nil},
+ },
+ },
+ {
+ description: "with payload",
+ wantBytes: []byte{
+ // IPv4 header
+ 0x45, 0x00, 0x00, 0x37, 0x00, 0x01, 0x00, 0x00, 0x40, 0x06,
+ 0xf9, 0x6c, 0xc0, 0xa8, 0x00, 0x02, 0xc0, 0xa8, 0x00, 0x01,
+ // TCP header
+ 0x30, 0x39, 0xd4, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x60, 0x02, 0x20, 0x00, 0xe5, 0x21, 0x00, 0x00,
+ // WindowScale Option
+ 0x03, 0x03, 0x02,
+ // NOP Option
+ 0x00,
+ // Payload: "Sample Data"
+ 0x53, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x20, 0x44, 0x61, 0x74, 0x61,
+ },
+ wantLayers: []Layer{
+ &IPv4{
+ IHL: Uint8(20),
+ TOS: Uint8(0),
+ TotalLength: Uint16(55),
+ ID: Uint16(1),
+ Flags: Uint8(0),
+ FragmentOffset: Uint16(0),
+ TTL: Uint8(64),
+ Protocol: Uint8(uint8(header.TCPProtocolNumber)),
+ Checksum: Uint16(0xf96c),
+ SrcAddr: Address(tcpip.Address(net.ParseIP("192.168.0.2").To4())),
+ DstAddr: Address(tcpip.Address(net.ParseIP("192.168.0.1").To4())),
+ },
+ &TCP{
+ SrcPort: Uint16(12345),
+ DstPort: Uint16(54321),
+ SeqNum: Uint32(0),
+ AckNum: Uint32(0),
+ Flags: Uint8(header.TCPFlagSyn),
+ WindowSize: Uint16(8192),
+ Checksum: Uint16(0xe521),
+ UrgentPointer: Uint16(0),
+ Options: []byte{3, 3, 2, 0},
+ },
+ &Payload{Bytes: []byte("Sample Data")},
+ },
+ },
+ } {
+ t.Run(tt.description, func(t *testing.T) {
+ layers := parse(parseIPv4, tt.wantBytes)
+ if !layers.match(tt.wantLayers) {
+ t.Fatalf("match failed with diff: %s", layers.diff(tt.wantLayers))
+ }
+ gotBytes, err := layers.ToBytes()
+ if err != nil {
+ t.Fatalf("ToBytes() failed on %s: %s", &layers, err)
+ }
+ if !bytes.Equal(tt.wantBytes, gotBytes) {
+ t.Fatalf("mismatching bytes, gotBytes: %x, wantBytes: %x", gotBytes, tt.wantBytes)
+ }
+ })
+ }
+}
diff --git a/test/packetimpact/tests/BUILD b/test/packetimpact/tests/BUILD
index c25b3b8c1..d4fcf31fa 100644
--- a/test/packetimpact/tests/BUILD
+++ b/test/packetimpact/tests/BUILD
@@ -19,7 +19,7 @@ packetimpact_go_test(
name = "udp_recv_multicast",
srcs = ["udp_recv_multicast_test.go"],
# TODO(b/152813495): Fix netstack then remove the line below.
- netstack = False,
+ expect_netstack_failure = True,
deps = [
"//pkg/tcpip",
"//pkg/tcpip/header",
@@ -32,7 +32,7 @@ packetimpact_go_test(
name = "udp_icmp_error_propagation",
srcs = ["udp_icmp_error_propagation_test.go"],
# TODO(b/153926291): Fix netstack then remove the line below.
- netstack = False,
+ expect_netstack_failure = True,
deps = [
"//pkg/tcpip",
"//pkg/tcpip/header",
@@ -82,6 +82,16 @@ packetimpact_go_test(
)
packetimpact_go_test(
+ name = "tcp_retransmits",
+ srcs = ["tcp_retransmits_test.go"],
+ deps = [
+ "//pkg/tcpip/header",
+ "//test/packetimpact/testbench",
+ "@org_golang_x_sys//unix:go_default_library",
+ ],
+)
+
+packetimpact_go_test(
name = "tcp_outside_the_window",
srcs = ["tcp_outside_the_window_test.go"],
deps = [
@@ -106,7 +116,7 @@ packetimpact_go_test(
name = "tcp_should_piggyback",
srcs = ["tcp_should_piggyback_test.go"],
# TODO(b/153680566): Fix netstack then remove the line below.
- netstack = False,
+ expect_netstack_failure = True,
deps = [
"//pkg/tcpip/header",
"//test/packetimpact/testbench",
@@ -139,7 +149,7 @@ packetimpact_go_test(
name = "icmpv6_param_problem",
srcs = ["icmpv6_param_problem_test.go"],
# TODO(b/153485026): Fix netstack then remove the line below.
- netstack = False,
+ expect_netstack_failure = True,
deps = [
"//pkg/tcpip",
"//pkg/tcpip/header",
diff --git a/test/packetimpact/tests/defs.bzl b/test/packetimpact/tests/defs.bzl
index 27c5de375..45dce64ab 100644
--- a/test/packetimpact/tests/defs.bzl
+++ b/test/packetimpact/tests/defs.bzl
@@ -106,15 +106,15 @@ def packetimpact_netstack_test(
**kwargs
)
-def packetimpact_go_test(name, size = "small", pure = True, linux = True, netstack = True, **kwargs):
+def packetimpact_go_test(name, size = "small", pure = True, expect_linux_failure = False, expect_netstack_failure = False, **kwargs):
"""Add packetimpact tests written in go.
Args:
name: name of the test
size: size of the test
pure: make a static go binary
- linux: generate a linux test
- netstack: generate a netstack test
+ expect_linux_failure: expect the test to fail for Linux
+ expect_netstack_failure: expect the test to fail for Netstack
**kwargs: all the other args, forwarded to go_test
"""
testbench_binary = name + "_test"
@@ -127,11 +127,11 @@ def packetimpact_go_test(name, size = "small", pure = True, linux = True, netsta
)
packetimpact_linux_test(
name = name,
- expect_failure = not linux,
+ expect_failure = expect_linux_failure,
testbench_binary = testbench_binary,
)
packetimpact_netstack_test(
name = name,
- expect_failure = not netstack,
+ expect_failure = expect_netstack_failure,
testbench_binary = testbench_binary,
)
diff --git a/test/packetimpact/tests/tcp_retransmits_test.go b/test/packetimpact/tests/tcp_retransmits_test.go
new file mode 100644
index 000000000..c043ad881
--- /dev/null
+++ b/test/packetimpact/tests/tcp_retransmits_test.go
@@ -0,0 +1,84 @@
+// Copyright 2020 The gVisor Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package tcp_retransmits_test
+
+import (
+ "flag"
+ "testing"
+ "time"
+
+ "golang.org/x/sys/unix"
+ "gvisor.dev/gvisor/pkg/tcpip/header"
+ tb "gvisor.dev/gvisor/test/packetimpact/testbench"
+)
+
+func init() {
+ tb.RegisterFlags(flag.CommandLine)
+}
+
+// TestRetransmits tests retransmits occur at exponentially increasing
+// time intervals.
+func TestRetransmits(t *testing.T) {
+ dut := tb.NewDUT(t)
+ defer dut.TearDown()
+ listenFd, remotePort := dut.CreateListener(unix.SOCK_STREAM, unix.IPPROTO_TCP, 1)
+ defer dut.Close(listenFd)
+ conn := tb.NewTCPIPv4(t, tb.TCP{DstPort: &remotePort}, tb.TCP{SrcPort: &remotePort})
+ defer conn.Close()
+
+ conn.Handshake()
+ acceptFd, _ := dut.Accept(listenFd)
+ defer dut.Close(acceptFd)
+
+ dut.SetSockOptInt(acceptFd, unix.IPPROTO_TCP, unix.TCP_NODELAY, 1)
+
+ sampleData := []byte("Sample Data")
+ samplePayload := &tb.Payload{Bytes: sampleData}
+
+ dut.Send(acceptFd, sampleData, 0)
+ if _, err := conn.ExpectData(&tb.TCP{}, samplePayload, time.Second); err != nil {
+ t.Fatalf("expected a packet with payload %v: %s", samplePayload, err)
+ }
+ // Give a chance for the dut to estimate RTO with RTT from the DATA-ACK.
+ // TODO(gvisor.dev/issue/2685) Estimate RTO during handshake, after which
+ // we can skip sending this ACK.
+ conn.Send(tb.TCP{Flags: tb.Uint8(header.TCPFlagAck)})
+
+ startRTO := time.Second
+ current := startRTO
+ first := time.Now()
+ dut.Send(acceptFd, sampleData, 0)
+ seq := tb.Uint32(uint32(*conn.RemoteSeqNum()))
+ if _, err := conn.ExpectData(&tb.TCP{SeqNum: seq}, samplePayload, startRTO); err != nil {
+ t.Fatalf("expected a packet with payload %v: %s", samplePayload, err)
+ }
+ // Expect retransmits of the same segment.
+ for i := 0; i < 5; i++ {
+ start := time.Now()
+ if _, err := conn.ExpectData(&tb.TCP{SeqNum: seq}, samplePayload, 2*current); err != nil {
+ t.Fatalf("expected a packet with payload %v: %s loop %d", samplePayload, err, i)
+ }
+ if i == 0 {
+ startRTO = time.Now().Sub(first)
+ current = 2 * startRTO
+ continue
+ }
+ // Check if the probes came at exponentially increasing intervals.
+ if p := time.Since(start); p < current-startRTO {
+ t.Fatalf("retransmit came sooner interval %d probe %d\n", p, i)
+ }
+ current *= 2
+ }
+}
diff --git a/test/syscalls/linux/BUILD b/test/syscalls/linux/BUILD
index adf259bba..5acdb8438 100644
--- a/test/syscalls/linux/BUILD
+++ b/test/syscalls/linux/BUILD
@@ -835,10 +835,7 @@ cc_binary(
cc_binary(
name = "fpsig_fork_test",
testonly = 1,
- srcs = select_arch(
- amd64 = ["fpsig_fork.cc"],
- arm64 = [],
- ),
+ srcs = ["fpsig_fork.cc"],
linkstatic = 1,
deps = [
gtest,
@@ -3288,6 +3285,7 @@ cc_binary(
"//test/util:capability_util",
"//test/util:file_descriptor",
"//test/util:fs_util",
+ "@com_google_absl//absl/time",
gtest,
"//test/util:temp_path",
"//test/util:test_main",
diff --git a/test/syscalls/linux/fpsig_fork.cc b/test/syscalls/linux/fpsig_fork.cc
index a346f1f00..d08111cd3 100644
--- a/test/syscalls/linux/fpsig_fork.cc
+++ b/test/syscalls/linux/fpsig_fork.cc
@@ -27,9 +27,22 @@ namespace testing {
namespace {
+#ifdef __x86_64__
#define GET_XMM(__var, __xmm) \
asm volatile("movq %%" #__xmm ", %0" : "=r"(__var))
#define SET_XMM(__var, __xmm) asm volatile("movq %0, %%" #__xmm : : "r"(__var))
+#define GET_FP0(__var) GET_XMM(__var, xmm0)
+#define SET_FP0(__var) SET_XMM(__var, xmm0)
+#elif __aarch64__
+#define __stringify_1(x...) #x
+#define __stringify(x...) __stringify_1(x)
+#define GET_FPREG(var, regname) \
+ asm volatile("str "__stringify(regname) ", %0" : "=m"(var))
+#define SET_FPREG(var, regname) \
+ asm volatile("ldr "__stringify(regname) ", %0" : "=m"(var))
+#define GET_FP0(var) GET_FPREG(var, d0)
+#define SET_FP0(var) GET_FPREG(var, d0)
+#endif
int parent, child;
@@ -40,7 +53,10 @@ void sigusr1(int s, siginfo_t* siginfo, void* _uc) {
TEST_CHECK_MSG(child >= 0, "fork failed");
uint64_t val = SIGUSR1;
- SET_XMM(val, xmm0);
+ SET_FP0(val);
+ uint64_t got;
+ GET_FP0(got);
+ TEST_CHECK_MSG(val == got, "Basic FP check failed in sigusr1()");
}
TEST(FPSigTest, Fork) {
@@ -67,8 +83,9 @@ TEST(FPSigTest, Fork) {
// be the one clobbered.
uint64_t expected = 0xdeadbeeffacefeed;
- SET_XMM(expected, xmm0);
+ SET_FP0(expected);
+#ifdef __x86_64__
asm volatile(
"movl %[killnr], %%eax;"
"movl %[parent], %%edi;"
@@ -81,9 +98,18 @@ TEST(FPSigTest, Fork) {
: "rax", "rdi", "rsi", "rdx",
// Clobbered by syscall.
"rcx", "r11");
+#elif __aarch64__
+ asm volatile(
+ "mov x8, %0\n"
+ "mov x0, %1\n"
+ "mov x1, %2\n"
+ "mov x2, %3\n"
+ "svc #0\n" ::"r"(__NR_tgkill),
+ "r"(parent), "r"(parent_tid), "r"(SIGUSR1));
+#endif
uint64_t got;
- GET_XMM(got, xmm0);
+ GET_FP0(got);
if (getpid() == parent) { // Parent.
int status;
diff --git a/test/syscalls/linux/itimer.cc b/test/syscalls/linux/itimer.cc
index dd981a278..e397d5f57 100644
--- a/test/syscalls/linux/itimer.cc
+++ b/test/syscalls/linux/itimer.cc
@@ -267,8 +267,19 @@ int TestSIGPROFFairness(absl::Duration sleep) {
// Random save/restore is disabled as it introduces additional latency and
// unpredictable distribution patterns.
TEST(ItimerTest, DeliversSIGPROFToThreadsRoughlyFairlyActive_NoRandomSave) {
- // TODO(b/143247272): CPU time accounting is inaccurate for the KVM platform.
- SKIP_IF(GvisorPlatform() == Platform::kKVM);
+ // On the KVM and ptrace platforms, switches between sentry and application
+ // context are sometimes extremely slow, causing the itimer to send SIGPROF to
+ // a thread that either already has one pending or has had SIGPROF delivered,
+ // but hasn't handled it yet (and thus therefore still has SIGPROF masked). In
+ // either case, since itimer signals are group-directed, signal sending falls
+ // back to notifying the thread group leader. ItimerSignalTest() fails if "too
+ // many" signals are delivered to the thread group leader, so these tests are
+ // flaky on these platforms.
+ //
+ // TODO(b/143247272): Clarify why context switches are so slow on KVM.
+ const auto gvisor_platform = GvisorPlatform();
+ SKIP_IF(gvisor_platform == Platform::kKVM ||
+ gvisor_platform == Platform::kPtrace);
pid_t child;
int execve_errno;
@@ -291,8 +302,10 @@ TEST(ItimerTest, DeliversSIGPROFToThreadsRoughlyFairlyActive_NoRandomSave) {
// Random save/restore is disabled as it introduces additional latency and
// unpredictable distribution patterns.
TEST(ItimerTest, DeliversSIGPROFToThreadsRoughlyFairlyIdle_NoRandomSave) {
- // TODO(b/143247272): CPU time accounting is inaccurate for the KVM platform.
- SKIP_IF(GvisorPlatform() == Platform::kKVM);
+ // See comment in DeliversSIGPROFToThreadsRoughlyFairlyActive.
+ const auto gvisor_platform = GvisorPlatform();
+ SKIP_IF(gvisor_platform == Platform::kKVM ||
+ gvisor_platform == Platform::kPtrace);
pid_t child;
int execve_errno;
diff --git a/test/syscalls/linux/socket.cc b/test/syscalls/linux/socket.cc
index 703d594a2..afa59c1da 100644
--- a/test/syscalls/linux/socket.cc
+++ b/test/syscalls/linux/socket.cc
@@ -61,7 +61,7 @@ TEST(SocketTest, ProtocolInet) {
}
}
-TEST(SocketTest, UnixSocketFileMode) {
+TEST(SocketTest, UnixSocketStat) {
// TODO(gvisor.dev/issue/1624): Re-enable this test once VFS1 is deleted. It
// should pass in VFS2.
SKIP_IF(IsRunningOnGvisor());
@@ -83,7 +83,14 @@ TEST(SocketTest, UnixSocketFileMode) {
struct stat statbuf = {};
ASSERT_THAT(stat(addr.sun_path, &statbuf), SyscallSucceeds());
+
+ // Mode should be S_IFSOCK.
EXPECT_EQ(statbuf.st_mode, S_IFSOCK | sock_perm & ~mask);
+
+ // Timestamps should be equal and non-zero.
+ EXPECT_NE(statbuf.st_atime, 0);
+ EXPECT_EQ(statbuf.st_atime, statbuf.st_mtime);
+ EXPECT_EQ(statbuf.st_atime, statbuf.st_ctime);
}
TEST(SocketTest, UnixConnectNeedsWritePerm) {
diff --git a/test/syscalls/linux/socket_ip_tcp_generic.cc b/test/syscalls/linux/socket_ip_tcp_generic.cc
index 27779e47c..fa81845fd 100644
--- a/test/syscalls/linux/socket_ip_tcp_generic.cc
+++ b/test/syscalls/linux/socket_ip_tcp_generic.cc
@@ -876,6 +876,51 @@ TEST_P(TCPSocketPairTest, SetTCPUserTimeoutAboveZero) {
EXPECT_EQ(get, kAbove);
}
+TEST_P(TCPSocketPairTest, SetTCPWindowClampBelowMinRcvBufConnectedSocket) {
+ auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair());
+ // Discover minimum receive buf by setting a really low value
+ // for the receive buffer.
+ constexpr int kZero = 0;
+ EXPECT_THAT(setsockopt(sockets->first_fd(), SOL_SOCKET, SO_RCVBUF, &kZero,
+ sizeof(kZero)),
+ SyscallSucceeds());
+
+ // Now retrieve the minimum value for SO_RCVBUF as the set above should
+ // have caused SO_RCVBUF for the socket to be set to the minimum.
+ int get = -1;
+ socklen_t get_len = sizeof(get);
+ ASSERT_THAT(
+ getsockopt(sockets->first_fd(), SOL_SOCKET, SO_RCVBUF, &get, &get_len),
+ SyscallSucceedsWithValue(0));
+ EXPECT_EQ(get_len, sizeof(get));
+ int min_so_rcvbuf = get;
+
+ {
+ // Setting TCP_WINDOW_CLAMP to zero for a connected socket is not permitted.
+ constexpr int kZero = 0;
+ EXPECT_THAT(setsockopt(sockets->first_fd(), IPPROTO_TCP, TCP_WINDOW_CLAMP,
+ &kZero, sizeof(kZero)),
+ SyscallFailsWithErrno(EINVAL));
+
+ // Non-zero clamp values below MIN_SO_RCVBUF/2 should result in the clamp
+ // being set to MIN_SO_RCVBUF/2.
+ int below_half_min_so_rcvbuf = min_so_rcvbuf / 2 - 1;
+ EXPECT_THAT(
+ setsockopt(sockets->first_fd(), IPPROTO_TCP, TCP_WINDOW_CLAMP,
+ &below_half_min_so_rcvbuf, sizeof(below_half_min_so_rcvbuf)),
+ SyscallSucceeds());
+
+ int get = -1;
+ socklen_t get_len = sizeof(get);
+
+ ASSERT_THAT(getsockopt(sockets->first_fd(), IPPROTO_TCP, TCP_WINDOW_CLAMP,
+ &get, &get_len),
+ SyscallSucceedsWithValue(0));
+ EXPECT_EQ(get_len, sizeof(get));
+ EXPECT_EQ(min_so_rcvbuf / 2, get);
+ }
+}
+
TEST_P(TCPSocketPairTest, TCPResetDuringClose_NoRandomSave) {
DisableSave ds; // Too many syscalls.
constexpr int kThreadCount = 1000;
diff --git a/test/syscalls/linux/symlink.cc b/test/syscalls/linux/symlink.cc
index 03ee1250d..a17ff62e9 100644
--- a/test/syscalls/linux/symlink.cc
+++ b/test/syscalls/linux/symlink.cc
@@ -20,6 +20,7 @@
#include <string>
#include "gtest/gtest.h"
+#include "absl/time/clock.h"
#include "test/util/capability_util.h"
#include "test/util/file_descriptor.h"
#include "test/util/fs_util.h"
@@ -272,6 +273,30 @@ TEST(SymlinkTest, ChmodSymlink) {
EXPECT_EQ(FilePermission(newpath), 0777);
}
+// Test that following a symlink updates the atime on the symlink.
+TEST(SymlinkTest, FollowUpdatesATime) {
+ const auto file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile());
+ const std::string link = NewTempAbsPath();
+ EXPECT_THAT(symlink(file.path().c_str(), link.c_str()), SyscallSucceeds());
+
+ // Lstat the symlink.
+ struct stat st_before_follow;
+ ASSERT_THAT(lstat(link.c_str(), &st_before_follow), SyscallSucceeds());
+
+ // Let the clock advance.
+ absl::SleepFor(absl::Seconds(1));
+
+ // Open the file via the symlink.
+ int fd;
+ ASSERT_THAT(fd = open(link.c_str(), O_RDWR, 0666), SyscallSucceeds());
+ FileDescriptor fd_closer(fd);
+
+ // Lstat the symlink again, and check that atime is updated.
+ struct stat st_after_follow;
+ ASSERT_THAT(lstat(link.c_str(), &st_after_follow), SyscallSucceeds());
+ EXPECT_LT(st_before_follow.st_atime, st_after_follow.st_atime);
+}
+
class ParamSymlinkTest : public ::testing::TestWithParam<std::string> {};
// Test that creating an existing symlink with creat will create the target.
diff --git a/test/syscalls/linux/tcp_socket.cc b/test/syscalls/linux/tcp_socket.cc
index d9c1ac0e1..a4d2953e1 100644
--- a/test/syscalls/linux/tcp_socket.cc
+++ b/test/syscalls/linux/tcp_socket.cc
@@ -1313,7 +1313,7 @@ TEST_P(SimpleTcpSocketTest, SetTCPDeferAcceptNeg) {
int get = -1;
socklen_t get_len = sizeof(get);
ASSERT_THAT(
- getsockopt(s.get(), IPPROTO_TCP, TCP_USER_TIMEOUT, &get, &get_len),
+ getsockopt(s.get(), IPPROTO_TCP, TCP_DEFER_ACCEPT, &get, &get_len),
SyscallSucceedsWithValue(0));
EXPECT_EQ(get_len, sizeof(get));
EXPECT_EQ(get, 0);
@@ -1326,7 +1326,7 @@ TEST_P(SimpleTcpSocketTest, GetTCPDeferAcceptDefault) {
int get = -1;
socklen_t get_len = sizeof(get);
ASSERT_THAT(
- getsockopt(s.get(), IPPROTO_TCP, TCP_USER_TIMEOUT, &get, &get_len),
+ getsockopt(s.get(), IPPROTO_TCP, TCP_DEFER_ACCEPT, &get, &get_len),
SyscallSucceedsWithValue(0));
EXPECT_EQ(get_len, sizeof(get));
EXPECT_EQ(get, 0);
@@ -1378,6 +1378,187 @@ TEST_P(SimpleTcpSocketTest, TCPConnectSoRcvBufRace) {
SyscallSucceedsWithValue(0));
}
+TEST_P(SimpleTcpSocketTest, SetTCPSynCntLessThanOne) {
+ FileDescriptor s =
+ ASSERT_NO_ERRNO_AND_VALUE(Socket(GetParam(), SOCK_STREAM, IPPROTO_TCP));
+
+ int get = -1;
+ socklen_t get_len = sizeof(get);
+ ASSERT_THAT(getsockopt(s.get(), IPPROTO_TCP, TCP_SYNCNT, &get, &get_len),
+ SyscallSucceedsWithValue(0));
+ EXPECT_EQ(get_len, sizeof(get));
+ int default_syn_cnt = get;
+
+ {
+ // TCP_SYNCNT less than 1 should be rejected with an EINVAL.
+ constexpr int kZero = 0;
+ EXPECT_THAT(
+ setsockopt(s.get(), IPPROTO_TCP, TCP_SYNCNT, &kZero, sizeof(kZero)),
+ SyscallFailsWithErrno(EINVAL));
+
+ // TCP_SYNCNT less than 1 should be rejected with an EINVAL.
+ constexpr int kNeg = -1;
+ EXPECT_THAT(
+ setsockopt(s.get(), IPPROTO_TCP, TCP_SYNCNT, &kNeg, sizeof(kNeg)),
+ SyscallFailsWithErrno(EINVAL));
+
+ int get = -1;
+ socklen_t get_len = sizeof(get);
+
+ ASSERT_THAT(getsockopt(s.get(), IPPROTO_TCP, TCP_SYNCNT, &get, &get_len),
+ SyscallSucceedsWithValue(0));
+ EXPECT_EQ(get_len, sizeof(get));
+ EXPECT_EQ(default_syn_cnt, get);
+ }
+}
+
+TEST_P(SimpleTcpSocketTest, GetTCPSynCntDefault) {
+ FileDescriptor s =
+ ASSERT_NO_ERRNO_AND_VALUE(Socket(GetParam(), SOCK_STREAM, IPPROTO_TCP));
+
+ int get = -1;
+ socklen_t get_len = sizeof(get);
+ constexpr int kDefaultSynCnt = 6;
+
+ ASSERT_THAT(getsockopt(s.get(), IPPROTO_TCP, TCP_SYNCNT, &get, &get_len),
+ SyscallSucceedsWithValue(0));
+ EXPECT_EQ(get_len, sizeof(get));
+ EXPECT_EQ(get, kDefaultSynCnt);
+}
+
+TEST_P(SimpleTcpSocketTest, SetTCPSynCntGreaterThanOne) {
+ FileDescriptor s =
+ ASSERT_NO_ERRNO_AND_VALUE(Socket(GetParam(), SOCK_STREAM, IPPROTO_TCP));
+ constexpr int kTCPSynCnt = 20;
+ ASSERT_THAT(setsockopt(s.get(), IPPROTO_TCP, TCP_SYNCNT, &kTCPSynCnt,
+ sizeof(kTCPSynCnt)),
+ SyscallSucceeds());
+
+ int get = -1;
+ socklen_t get_len = sizeof(get);
+ ASSERT_THAT(getsockopt(s.get(), IPPROTO_TCP, TCP_SYNCNT, &get, &get_len),
+ SyscallSucceeds());
+ EXPECT_EQ(get_len, sizeof(get));
+ EXPECT_EQ(get, kTCPSynCnt);
+}
+
+TEST_P(SimpleTcpSocketTest, SetTCPSynCntAboveMax) {
+ FileDescriptor s =
+ ASSERT_NO_ERRNO_AND_VALUE(Socket(GetParam(), SOCK_STREAM, IPPROTO_TCP));
+ int get = -1;
+ socklen_t get_len = sizeof(get);
+ ASSERT_THAT(getsockopt(s.get(), IPPROTO_TCP, TCP_SYNCNT, &get, &get_len),
+ SyscallSucceedsWithValue(0));
+ EXPECT_EQ(get_len, sizeof(get));
+ int default_syn_cnt = get;
+ {
+ constexpr int kTCPSynCnt = 256;
+ ASSERT_THAT(setsockopt(s.get(), IPPROTO_TCP, TCP_SYNCNT, &kTCPSynCnt,
+ sizeof(kTCPSynCnt)),
+ SyscallFailsWithErrno(EINVAL));
+
+ int get = -1;
+ socklen_t get_len = sizeof(get);
+ ASSERT_THAT(getsockopt(s.get(), IPPROTO_TCP, TCP_SYNCNT, &get, &get_len),
+ SyscallSucceeds());
+ EXPECT_EQ(get_len, sizeof(get));
+ EXPECT_EQ(get, default_syn_cnt);
+ }
+}
+
+TEST_P(SimpleTcpSocketTest, SetTCPWindowClampBelowMinRcvBuf) {
+ FileDescriptor s =
+ ASSERT_NO_ERRNO_AND_VALUE(Socket(GetParam(), SOCK_STREAM, IPPROTO_TCP));
+
+ // Discover minimum receive buf by setting a really low value
+ // for the receive buffer.
+ constexpr int kZero = 0;
+ EXPECT_THAT(setsockopt(s.get(), SOL_SOCKET, SO_RCVBUF, &kZero, sizeof(kZero)),
+ SyscallSucceeds());
+
+ // Now retrieve the minimum value for SO_RCVBUF as the set above should
+ // have caused SO_RCVBUF for the socket to be set to the minimum.
+ int get = -1;
+ socklen_t get_len = sizeof(get);
+ ASSERT_THAT(getsockopt(s.get(), SOL_SOCKET, SO_RCVBUF, &get, &get_len),
+ SyscallSucceedsWithValue(0));
+ EXPECT_EQ(get_len, sizeof(get));
+ int min_so_rcvbuf = get;
+
+ {
+ // TCP_WINDOW_CLAMP less than min_so_rcvbuf/2 should be set to
+ // min_so_rcvbuf/2.
+ int below_half_min_rcvbuf = min_so_rcvbuf / 2 - 1;
+ EXPECT_THAT(
+ setsockopt(s.get(), IPPROTO_TCP, TCP_WINDOW_CLAMP,
+ &below_half_min_rcvbuf, sizeof(below_half_min_rcvbuf)),
+ SyscallSucceeds());
+
+ int get = -1;
+ socklen_t get_len = sizeof(get);
+
+ ASSERT_THAT(
+ getsockopt(s.get(), IPPROTO_TCP, TCP_WINDOW_CLAMP, &get, &get_len),
+ SyscallSucceedsWithValue(0));
+ EXPECT_EQ(get_len, sizeof(get));
+ EXPECT_EQ(min_so_rcvbuf / 2, get);
+ }
+}
+
+TEST_P(SimpleTcpSocketTest, SetTCPWindowClampZeroClosedSocket) {
+ FileDescriptor s =
+ ASSERT_NO_ERRNO_AND_VALUE(Socket(GetParam(), SOCK_STREAM, IPPROTO_TCP));
+ constexpr int kZero = 0;
+ ASSERT_THAT(
+ setsockopt(s.get(), IPPROTO_TCP, TCP_WINDOW_CLAMP, &kZero, sizeof(kZero)),
+ SyscallSucceeds());
+
+ int get = -1;
+ socklen_t get_len = sizeof(get);
+ ASSERT_THAT(
+ getsockopt(s.get(), IPPROTO_TCP, TCP_WINDOW_CLAMP, &get, &get_len),
+ SyscallSucceeds());
+ EXPECT_EQ(get_len, sizeof(get));
+ EXPECT_EQ(get, kZero);
+}
+
+TEST_P(SimpleTcpSocketTest, SetTCPWindowClampAboveHalfMinRcvBuf) {
+ FileDescriptor s =
+ ASSERT_NO_ERRNO_AND_VALUE(Socket(GetParam(), SOCK_STREAM, IPPROTO_TCP));
+
+ // Discover minimum receive buf by setting a really low value
+ // for the receive buffer.
+ constexpr int kZero = 0;
+ EXPECT_THAT(setsockopt(s.get(), SOL_SOCKET, SO_RCVBUF, &kZero, sizeof(kZero)),
+ SyscallSucceeds());
+
+ // Now retrieve the minimum value for SO_RCVBUF as the set above should
+ // have caused SO_RCVBUF for the socket to be set to the minimum.
+ int get = -1;
+ socklen_t get_len = sizeof(get);
+ ASSERT_THAT(getsockopt(s.get(), SOL_SOCKET, SO_RCVBUF, &get, &get_len),
+ SyscallSucceedsWithValue(0));
+ EXPECT_EQ(get_len, sizeof(get));
+ int min_so_rcvbuf = get;
+
+ {
+ int above_half_min_rcv_buf = min_so_rcvbuf / 2 + 1;
+ EXPECT_THAT(
+ setsockopt(s.get(), IPPROTO_TCP, TCP_WINDOW_CLAMP,
+ &above_half_min_rcv_buf, sizeof(above_half_min_rcv_buf)),
+ SyscallSucceeds());
+
+ int get = -1;
+ socklen_t get_len = sizeof(get);
+
+ ASSERT_THAT(
+ getsockopt(s.get(), IPPROTO_TCP, TCP_WINDOW_CLAMP, &get, &get_len),
+ SyscallSucceedsWithValue(0));
+ EXPECT_EQ(get_len, sizeof(get));
+ EXPECT_EQ(above_half_min_rcv_buf, get);
+ }
+}
+
INSTANTIATE_TEST_SUITE_P(AllInetTests, SimpleTcpSocketTest,
::testing::Values(AF_INET, AF_INET6));
diff --git a/test/syscalls/linux/udp_socket_test_cases.cc b/test/syscalls/linux/udp_socket_test_cases.cc
index 740c7986d..4a3ae5f3f 100644
--- a/test/syscalls/linux/udp_socket_test_cases.cc
+++ b/test/syscalls/linux/udp_socket_test_cases.cc
@@ -17,6 +17,7 @@
#include <arpa/inet.h>
#include <fcntl.h>
#include <netinet/in.h>
+#include <poll.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/types.h>
@@ -673,6 +674,11 @@ TEST_P(UdpSocketTest, ZerolengthWriteAllowed) {
char buf[3];
// Send zero length packet from s_ to t_.
ASSERT_THAT(write(s_, buf, 0), SyscallSucceedsWithValue(0));
+
+ struct pollfd pfd = {t_, POLLIN, 0};
+ ASSERT_THAT(RetryEINTR(poll)(&pfd, 1, /*timeout=*/1000),
+ SyscallSucceedsWithValue(1));
+
// Receive the packet.
char received[3];
EXPECT_THAT(read(t_, received, sizeof(received)),
@@ -698,6 +704,11 @@ TEST_P(UdpSocketTest, ZerolengthWriteAllowedNonBlockRead) {
char buf[3];
// Send zero length packet from s_ to t_.
ASSERT_THAT(write(s_, buf, 0), SyscallSucceedsWithValue(0));
+
+ struct pollfd pfd = {t_, POLLIN, 0};
+ ASSERT_THAT(RetryEINTR(poll)(&pfd, 1, /*timeout=*/1000),
+ SyscallSucceedsWithValue(1));
+
// Receive the packet.
char received[3];
EXPECT_THAT(read(t_, received, sizeof(received)),
@@ -859,6 +870,10 @@ TEST_P(UdpSocketTest, ReadShutdownNonblockPendingData) {
EXPECT_THAT(shutdown(s_, SHUT_RD), SyscallSucceeds());
+ struct pollfd pfd = {s_, POLLIN, 0};
+ ASSERT_THAT(RetryEINTR(poll)(&pfd, 1, /*timeout=*/1000),
+ SyscallSucceedsWithValue(1));
+
// We should get the data even though read has been shutdown.
EXPECT_THAT(recv(s_, received, 2, 0), SyscallSucceedsWithValue(2));
@@ -1112,6 +1127,10 @@ TEST_P(UdpSocketTest, FIONREADWriteShutdown) {
ASSERT_THAT(send(s_, str, sizeof(str), 0),
SyscallSucceedsWithValue(sizeof(str)));
+ struct pollfd pfd = {s_, POLLIN, 0};
+ ASSERT_THAT(RetryEINTR(poll)(&pfd, 1, /*timeout=*/1000),
+ SyscallSucceedsWithValue(1));
+
n = -1;
EXPECT_THAT(ioctl(s_, FIONREAD, &n), SyscallSucceedsWithValue(0));
EXPECT_EQ(n, sizeof(str));
@@ -1123,7 +1142,7 @@ TEST_P(UdpSocketTest, FIONREADWriteShutdown) {
EXPECT_EQ(n, sizeof(str));
}
-TEST_P(UdpSocketTest, Fionread) {
+TEST_P(UdpSocketTest, FIONREAD) {
// Bind s_ to loopback:TestPort.
ASSERT_THAT(bind(s_, addr_[0], addrlen_), SyscallSucceeds());
@@ -1138,10 +1157,14 @@ TEST_P(UdpSocketTest, Fionread) {
char buf[3 * psize];
RandomizeBuffer(buf, sizeof(buf));
+ struct pollfd pfd = {s_, POLLIN, 0};
for (int i = 0; i < 3; ++i) {
ASSERT_THAT(sendto(t_, buf + i * psize, psize, 0, addr_[0], addrlen_),
SyscallSucceedsWithValue(psize));
+ ASSERT_THAT(RetryEINTR(poll)(&pfd, 1, /*timeout=*/1000),
+ SyscallSucceedsWithValue(1));
+
// Check that regardless of how many packets are in the queue, the size
// reported is that of a single packet.
n = -1;
@@ -1165,10 +1188,18 @@ TEST_P(UdpSocketTest, FIONREADZeroLengthPacket) {
char buf[3 * psize];
RandomizeBuffer(buf, sizeof(buf));
+ struct pollfd pfd = {s_, POLLIN, 0};
for (int i = 0; i < 3; ++i) {
ASSERT_THAT(sendto(t_, buf + i * psize, 0, 0, addr_[0], addrlen_),
SyscallSucceedsWithValue(0));
+ // TODO(gvisor.dev/issue/2726): sending a zero-length message to a hostinet
+ // socket does not cause a poll event to be triggered.
+ if (!IsRunningWithHostinet()) {
+ ASSERT_THAT(RetryEINTR(poll)(&pfd, 1, /*timeout=*/1000),
+ SyscallSucceedsWithValue(1));
+ }
+
// Check that regardless of how many packets are in the queue, the size
// reported is that of a single packet.
n = -1;
@@ -1235,6 +1266,10 @@ TEST_P(UdpSocketTest, SoTimestamp) {
// Send zero length packet from t_ to s_.
ASSERT_THAT(RetryEINTR(write)(t_, buf, 0), SyscallSucceedsWithValue(0));
+ struct pollfd pfd = {s_, POLLIN, 0};
+ ASSERT_THAT(RetryEINTR(poll)(&pfd, 1, /*timeout=*/1000),
+ SyscallSucceedsWithValue(1));
+
char cmsgbuf[CMSG_SPACE(sizeof(struct timeval))];
msghdr msg;
memset(&msg, 0, sizeof(msg));
@@ -1278,6 +1313,10 @@ TEST_P(UdpSocketTest, TimestampIoctl) {
ASSERT_THAT(RetryEINTR(write)(t_, buf, sizeof(buf)),
SyscallSucceedsWithValue(sizeof(buf)));
+ struct pollfd pfd = {s_, POLLIN, 0};
+ ASSERT_THAT(RetryEINTR(poll)(&pfd, 1, /*timeout=*/1000),
+ SyscallSucceedsWithValue(1));
+
// There should be no control messages.
char recv_buf[sizeof(buf)];
ASSERT_NO_FATAL_FAILURE(RecvNoCmsg(s_, recv_buf, sizeof(recv_buf)));
@@ -1315,6 +1354,10 @@ TEST_P(UdpSocketTest, TimestampIoctlPersistence) {
SyscallSucceedsWithValue(sizeof(buf)));
ASSERT_THAT(RetryEINTR(write)(t_, buf, 0), SyscallSucceedsWithValue(0));
+ struct pollfd pfd = {s_, POLLIN, 0};
+ ASSERT_THAT(RetryEINTR(poll)(&pfd, 1, /*timeout=*/1000),
+ SyscallSucceedsWithValue(1));
+
// There should be no control messages.
char recv_buf[sizeof(buf)];
ASSERT_NO_FATAL_FAILURE(RecvNoCmsg(s_, recv_buf, sizeof(recv_buf)));
@@ -1330,6 +1373,9 @@ TEST_P(UdpSocketTest, TimestampIoctlPersistence) {
SyscallSucceeds());
ASSERT_THAT(RetryEINTR(write)(t_, buf, 0), SyscallSucceedsWithValue(0));
+ ASSERT_THAT(RetryEINTR(poll)(&pfd, 1, /*timeout=*/1000),
+ SyscallSucceedsWithValue(1));
+
// There should be a message for SO_TIMESTAMP.
char cmsgbuf[CMSG_SPACE(sizeof(struct timeval))];
msghdr msg = {};
diff --git a/test/syscalls/linux/utimes.cc b/test/syscalls/linux/utimes.cc
index 22e6d1a85..e647d2896 100644
--- a/test/syscalls/linux/utimes.cc
+++ b/test/syscalls/linux/utimes.cc
@@ -48,12 +48,15 @@ void TimeBoxed(absl::Time* before, absl::Time* after,
// filesystems set it to 1, so we don't do any truncation.
struct timespec ts;
EXPECT_THAT(clock_gettime(CLOCK_REALTIME_COARSE, &ts), SyscallSucceeds());
- *before = absl::TimeFromTimespec(ts);
+ // FIXME(b/132819225): gVisor filesystem timestamps inconsistently use the
+ // internal or host clock, which may diverge slightly. Allow some slack on
+ // times to account for the difference.
+ *before = absl::TimeFromTimespec(ts) - absl::Seconds(1);
fn();
EXPECT_THAT(clock_gettime(CLOCK_REALTIME_COARSE, &ts), SyscallSucceeds());
- *after = absl::TimeFromTimespec(ts);
+ *after = absl::TimeFromTimespec(ts) + absl::Seconds(1);
if (*after < *before) {
// Clock jumped backwards; retry.
@@ -68,11 +71,11 @@ void TimeBoxed(absl::Time* before, absl::Time* after,
void TestUtimesOnPath(std::string const& path) {
struct stat statbuf;
- struct timeval times[2] = {{1, 0}, {2, 0}};
+ struct timeval times[2] = {{10, 0}, {20, 0}};
EXPECT_THAT(utimes(path.c_str(), times), SyscallSucceeds());
EXPECT_THAT(stat(path.c_str(), &statbuf), SyscallSucceeds());
- EXPECT_EQ(1, statbuf.st_atime);
- EXPECT_EQ(2, statbuf.st_mtime);
+ EXPECT_EQ(10, statbuf.st_atime);
+ EXPECT_EQ(20, statbuf.st_mtime);
absl::Time before;
absl::Time after;
@@ -103,18 +106,18 @@ TEST(UtimesTest, OnDir) {
TEST(UtimesTest, MissingPath) {
auto path = NewTempAbsPath();
- struct timeval times[2] = {{1, 0}, {2, 0}};
+ struct timeval times[2] = {{10, 0}, {20, 0}};
EXPECT_THAT(utimes(path.c_str(), times), SyscallFailsWithErrno(ENOENT));
}
void TestFutimesat(int dirFd, std::string const& path) {
struct stat statbuf;
- struct timeval times[2] = {{1, 0}, {2, 0}};
+ struct timeval times[2] = {{10, 0}, {20, 0}};
EXPECT_THAT(futimesat(dirFd, path.c_str(), times), SyscallSucceeds());
EXPECT_THAT(fstatat(dirFd, path.c_str(), &statbuf, 0), SyscallSucceeds());
- EXPECT_EQ(1, statbuf.st_atime);
- EXPECT_EQ(2, statbuf.st_mtime);
+ EXPECT_EQ(10, statbuf.st_atime);
+ EXPECT_EQ(20, statbuf.st_mtime);
absl::Time before;
absl::Time after;
@@ -175,11 +178,11 @@ TEST(FutimesatTest, InvalidNsec) {
void TestUtimensat(int dirFd, std::string const& path) {
struct stat statbuf;
- const struct timespec times[2] = {{1, 0}, {2, 0}};
+ const struct timespec times[2] = {{10, 0}, {20, 0}};
EXPECT_THAT(utimensat(dirFd, path.c_str(), times, 0), SyscallSucceeds());
EXPECT_THAT(fstatat(dirFd, path.c_str(), &statbuf, 0), SyscallSucceeds());
- EXPECT_EQ(1, statbuf.st_atime);
- EXPECT_EQ(2, statbuf.st_mtime);
+ EXPECT_EQ(10, statbuf.st_atime);
+ EXPECT_EQ(20, statbuf.st_mtime);
// Test setting with UTIME_NOW and UTIME_OMIT.
struct stat statbuf2;
@@ -301,13 +304,13 @@ TEST(Utimensat, NullPath) {
auto f = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile());
const FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE(Open(f.path(), O_RDWR));
struct stat statbuf;
- const struct timespec times[2] = {{1, 0}, {2, 0}};
+ const struct timespec times[2] = {{10, 0}, {20, 0}};
// Call syscall directly.
EXPECT_THAT(syscall(SYS_utimensat, fd.get(), NULL, times, 0),
SyscallSucceeds());
EXPECT_THAT(fstatat(0, f.path().c_str(), &statbuf, 0), SyscallSucceeds());
- EXPECT_EQ(1, statbuf.st_atime);
- EXPECT_EQ(2, statbuf.st_mtime);
+ EXPECT_EQ(10, statbuf.st_atime);
+ EXPECT_EQ(20, statbuf.st_mtime);
}
} // namespace