diff --git a/internal/errorsx/errno.go b/internal/errorsx/errno.go index abc19bb..5c57ff1 100644 --- a/internal/errorsx/errno.go +++ b/internal/errorsx/errno.go @@ -1,5 +1,5 @@ // Code generated by go generate; DO NOT EDIT. -// Generated: 2021-07-02 15:15:17.997258 +0200 CEST m=+0.110031584 +// Generated: 2021-07-02 17:54:06.182341 +0200 CEST m=+0.120124584 package errorsx @@ -10,6 +10,42 @@ import ( "syscall" ) +// This enumeration lists the syscall-derived failures defined at +// https://github.com/ooni/spec/blob/master/data-formats/df-007-errors.md +// +// See also the enumeration at failures.go for the failures that +// DO NOT derive from system call errors. +const ( + FailureOperationCanceled = "operation_canceled" + FailureConnectionRefused = "connection_refused" + FailureConnectionReset = "connection_reset" + FailureHostUnreachable = "host_unreachable" + FailureTimedOut = "timed_out" + FailureAddressFamilyNotSupported = "address_family_not_supported" + FailureAddressInUse = "address_in_use" + FailureAddressNotAvailable = "address_not_available" + FailureAlreadyConnected = "already_connected" + FailureBadAddress = "bad_address" + FailureBadFileDescriptor = "bad_file_descriptor" + FailureConnectionAborted = "connection_aborted" + FailureConnectionAlreadyInProgress = "connection_already_in_progress" + FailureDestinationAddressRequired = "destination_address_required" + FailureInterrupted = "interrupted" + FailureInvalidArgument = "invalid_argument" + FailureMessageSize = "message_size" + FailureNetworkDown = "network_down" + FailureNetworkReset = "network_reset" + FailureNetworkUnreachable = "network_unreachable" + FailureNoBufferSpace = "no_buffer_space" + FailureNoProtocolOption = "no_protocol_option" + FailureNotASocket = "not_a_socket" + FailureNotConnected = "not_connected" + FailureOperationWouldBlock = "operation_would_block" + FailurePermissionDenied = "permission_denied" + FailureProtocolNotSupported = "protocol_not_supported" + FailureWrongProtocolType = "wrong_protocol_type" +) + // toSyscallErr converts a syscall error to the // proper OONI error. Returns the OONI error string // on success, an empty string otherwise. @@ -23,7 +59,7 @@ func toSyscallErr(err error) string { } switch errno { case ECANCELED: - return FailureInterrupted + return FailureOperationCanceled case ECONNREFUSED: return FailureConnectionRefused case ECONNRESET: @@ -31,7 +67,53 @@ func toSyscallErr(err error) string { case EHOSTUNREACH: return FailureHostUnreachable case ETIMEDOUT: - return FailureGenericTimeoutError + return FailureTimedOut + case EAFNOSUPPORT: + return FailureAddressFamilyNotSupported + case EADDRINUSE: + return FailureAddressInUse + case EADDRNOTAVAIL: + return FailureAddressNotAvailable + case EISCONN: + return FailureAlreadyConnected + case EFAULT: + return FailureBadAddress + case EBADF: + return FailureBadFileDescriptor + case ECONNABORTED: + return FailureConnectionAborted + case EALREADY: + return FailureConnectionAlreadyInProgress + case EDESTADDRREQ: + return FailureDestinationAddressRequired + case EINTR: + return FailureInterrupted + case EINVAL: + return FailureInvalidArgument + case EMSGSIZE: + return FailureMessageSize + case ENETDOWN: + return FailureNetworkDown + case ENETRESET: + return FailureNetworkReset + case ENETUNREACH: + return FailureNetworkUnreachable + case ENOBUFS: + return FailureNoBufferSpace + case ENOPROTOOPT: + return FailureNoProtocolOption + case ENOTSOCK: + return FailureNotASocket + case ENOTCONN: + return FailureNotConnected + case EWOULDBLOCK: + return FailureOperationWouldBlock + case EACCES: + return FailurePermissionDenied + case EPROTONOSUPPORT: + return FailureProtocolNotSupported + case EPROTOTYPE: + return FailureWrongProtocolType } return "" } diff --git a/internal/errorsx/errno_test.go b/internal/errorsx/errno_test.go new file mode 100644 index 0000000..409acc6 --- /dev/null +++ b/internal/errorsx/errno_test.go @@ -0,0 +1,103 @@ +// Code generated by go generate; DO NOT EDIT. +// Generated: 2021-07-02 17:54:06.226224 +0200 CEST m=+0.164008293 + +package errorsx + +import ( + "io" + "syscall" + "testing" +) + +func TestToSyscallErr(t *testing.T) { + if v := toSyscallErr(io.EOF); v != "" { + t.Fatalf("expected empty string, got '%s'", v) + } + if v := toSyscallErr(ECANCELED); v != FailureOperationCanceled { + t.Fatalf("expected '%s', got '%s'", FailureOperationCanceled, v) + } + if v := toSyscallErr(ECONNREFUSED); v != FailureConnectionRefused { + t.Fatalf("expected '%s', got '%s'", FailureConnectionRefused, v) + } + if v := toSyscallErr(ECONNRESET); v != FailureConnectionReset { + t.Fatalf("expected '%s', got '%s'", FailureConnectionReset, v) + } + if v := toSyscallErr(EHOSTUNREACH); v != FailureHostUnreachable { + t.Fatalf("expected '%s', got '%s'", FailureHostUnreachable, v) + } + if v := toSyscallErr(ETIMEDOUT); v != FailureTimedOut { + t.Fatalf("expected '%s', got '%s'", FailureTimedOut, v) + } + if v := toSyscallErr(EAFNOSUPPORT); v != FailureAddressFamilyNotSupported { + t.Fatalf("expected '%s', got '%s'", FailureAddressFamilyNotSupported, v) + } + if v := toSyscallErr(EADDRINUSE); v != FailureAddressInUse { + t.Fatalf("expected '%s', got '%s'", FailureAddressInUse, v) + } + if v := toSyscallErr(EADDRNOTAVAIL); v != FailureAddressNotAvailable { + t.Fatalf("expected '%s', got '%s'", FailureAddressNotAvailable, v) + } + if v := toSyscallErr(EISCONN); v != FailureAlreadyConnected { + t.Fatalf("expected '%s', got '%s'", FailureAlreadyConnected, v) + } + if v := toSyscallErr(EFAULT); v != FailureBadAddress { + t.Fatalf("expected '%s', got '%s'", FailureBadAddress, v) + } + if v := toSyscallErr(EBADF); v != FailureBadFileDescriptor { + t.Fatalf("expected '%s', got '%s'", FailureBadFileDescriptor, v) + } + if v := toSyscallErr(ECONNABORTED); v != FailureConnectionAborted { + t.Fatalf("expected '%s', got '%s'", FailureConnectionAborted, v) + } + if v := toSyscallErr(EALREADY); v != FailureConnectionAlreadyInProgress { + t.Fatalf("expected '%s', got '%s'", FailureConnectionAlreadyInProgress, v) + } + if v := toSyscallErr(EDESTADDRREQ); v != FailureDestinationAddressRequired { + t.Fatalf("expected '%s', got '%s'", FailureDestinationAddressRequired, v) + } + if v := toSyscallErr(EINTR); v != FailureInterrupted { + t.Fatalf("expected '%s', got '%s'", FailureInterrupted, v) + } + if v := toSyscallErr(EINVAL); v != FailureInvalidArgument { + t.Fatalf("expected '%s', got '%s'", FailureInvalidArgument, v) + } + if v := toSyscallErr(EMSGSIZE); v != FailureMessageSize { + t.Fatalf("expected '%s', got '%s'", FailureMessageSize, v) + } + if v := toSyscallErr(ENETDOWN); v != FailureNetworkDown { + t.Fatalf("expected '%s', got '%s'", FailureNetworkDown, v) + } + if v := toSyscallErr(ENETRESET); v != FailureNetworkReset { + t.Fatalf("expected '%s', got '%s'", FailureNetworkReset, v) + } + if v := toSyscallErr(ENETUNREACH); v != FailureNetworkUnreachable { + t.Fatalf("expected '%s', got '%s'", FailureNetworkUnreachable, v) + } + if v := toSyscallErr(ENOBUFS); v != FailureNoBufferSpace { + t.Fatalf("expected '%s', got '%s'", FailureNoBufferSpace, v) + } + if v := toSyscallErr(ENOPROTOOPT); v != FailureNoProtocolOption { + t.Fatalf("expected '%s', got '%s'", FailureNoProtocolOption, v) + } + if v := toSyscallErr(ENOTSOCK); v != FailureNotASocket { + t.Fatalf("expected '%s', got '%s'", FailureNotASocket, v) + } + if v := toSyscallErr(ENOTCONN); v != FailureNotConnected { + t.Fatalf("expected '%s', got '%s'", FailureNotConnected, v) + } + if v := toSyscallErr(EWOULDBLOCK); v != FailureOperationWouldBlock { + t.Fatalf("expected '%s', got '%s'", FailureOperationWouldBlock, v) + } + if v := toSyscallErr(EACCES); v != FailurePermissionDenied { + t.Fatalf("expected '%s', got '%s'", FailurePermissionDenied, v) + } + if v := toSyscallErr(EPROTONOSUPPORT); v != FailureProtocolNotSupported { + t.Fatalf("expected '%s', got '%s'", FailureProtocolNotSupported, v) + } + if v := toSyscallErr(EPROTOTYPE); v != FailureWrongProtocolType { + t.Fatalf("expected '%s', got '%s'", FailureWrongProtocolType, v) + } + if v := toSyscallErr(syscall.Errno(0)); v != "" { + t.Fatalf("expected empty string, got '%s'", v) + } +} diff --git a/internal/errorsx/errno_unix.go b/internal/errorsx/errno_unix.go index 3b4cc50..5776423 100644 --- a/internal/errorsx/errno_unix.go +++ b/internal/errorsx/errno_unix.go @@ -1,5 +1,5 @@ // Code generated by go generate; DO NOT EDIT. -// Generated: 2021-07-02 15:15:17.887594 +0200 CEST m=+0.000365001 +// Generated: 2021-07-02 17:54:06.062944 +0200 CEST m=+0.000724793 package errorsx diff --git a/internal/errorsx/errno_windows.go b/internal/errorsx/errno_windows.go index 8e7f08f..0b35ab9 100644 --- a/internal/errorsx/errno_windows.go +++ b/internal/errorsx/errno_windows.go @@ -1,5 +1,5 @@ // Code generated by go generate; DO NOT EDIT. -// Generated: 2021-07-02 15:15:17.971155 +0200 CEST m=+0.083928418 +// Generated: 2021-07-02 17:54:06.155868 +0200 CEST m=+0.093650376 package errorsx diff --git a/internal/errorsx/errorsx_test.go b/internal/errorsx/errorsx_test.go index 6d34825..c60ebc2 100644 --- a/internal/errorsx/errorsx_test.go +++ b/internal/errorsx/errorsx_test.go @@ -54,7 +54,7 @@ func TestToFailureString(t *testing.T) { } }) t.Run("for canceled", func(t *testing.T) { - if toFailureString(syscall.ECANCELED) != FailureInterrupted { + if toFailureString(syscall.ECANCELED) != FailureOperationCanceled { t.Fatal("unexpected results") } }) @@ -74,7 +74,7 @@ func TestToFailureString(t *testing.T) { } }) t.Run("for system timeout", func(t *testing.T) { - if toFailureString(syscall.ETIMEDOUT) != FailureGenericTimeoutError { + if toFailureString(syscall.ETIMEDOUT) != FailureTimedOut { t.Fatal("unexpected results") } }) diff --git a/internal/errorsx/failures.go b/internal/errorsx/failures.go index 70b5109..84a7103 100644 --- a/internal/errorsx/failures.go +++ b/internal/errorsx/failures.go @@ -1,14 +1,11 @@ package errorsx -// This enumeration lists all the failures defined at +// This enumeration lists the non-syscall-derived failures defined at // https://github.com/ooni/spec/blob/master/data-formats/df-007-errors.md +// +// See also the enumeration at errno.go for the failures that +// derive directly from system call errors. const ( - // FailureConnectionRefused means ECONNREFUSED. - FailureConnectionRefused = "connection_refused" - - // FailureConnectionReset means ECONNRESET. - FailureConnectionReset = "connection_reset" - // FailureDNSBogonError means we detected bogon in DNS reply. FailureDNSBogonError = "dns_bogon_error" @@ -21,12 +18,6 @@ const ( // FailureGenericTimeoutError means we got some timer has expired. FailureGenericTimeoutError = "generic_timeout_error" - // FailureHostUnreachable means that there is "no route to host". - FailureHostUnreachable = "host_unreachable" - - // FailureInterrupted means that the user interrupted us. - FailureInterrupted = "interrupted" - // FailureNoCompatibleQUICVersion means that the server does not support the proposed QUIC version FailureNoCompatibleQUICVersion = "quic_incompatible_version" diff --git a/internal/errorsx/generator/main.go b/internal/errorsx/generator/main.go index 2c5019b..98e1dff 100644 --- a/internal/errorsx/generator/main.go +++ b/internal/errorsx/generator/main.go @@ -6,6 +6,7 @@ import ( "os" "time" + "github.com/iancoleman/strcase" "golang.org/x/sys/execabs" ) @@ -18,13 +19,10 @@ type ErrorSpec struct { Failure string } -// TODO(kelmenhorst): find out if we need more system errors here. Currently -// the code does not generate any mapping if Failure is empty. - // Specs contains all the error specs. var Specs = []ErrorSpec{{ Errno: "ECANCELED", - Failure: "Interrupted", + Failure: "OperationCanceled", }, { Errno: "ECONNREFUSED", Failure: "ConnectionRefused", @@ -36,53 +34,76 @@ var Specs = []ErrorSpec{{ Failure: "HostUnreachable", }, { Errno: "ETIMEDOUT", - Failure: "GenericTimeoutError", + Failure: "TimedOut", }, { - Errno: "EAFNOSUPPORT", + Errno: "EAFNOSUPPORT", + Failure: "AddressFamilyNotSupported", }, { - Errno: "EADDRINUSE", + Errno: "EADDRINUSE", + Failure: "AddressInUse", }, { - Errno: "EADDRNOTAVAIL", + Errno: "EADDRNOTAVAIL", + Failure: "AddressNotAvailable", }, { - Errno: "EISCONN", + Errno: "EISCONN", + Failure: "AlreadyConnected", }, { - Errno: "EFAULT", + Errno: "EFAULT", + Failure: "BadAddress", }, { - Errno: "EBADF", + Errno: "EBADF", + Failure: "BadFileDescriptor", }, { - Errno: "ECONNABORTED", + Errno: "ECONNABORTED", + Failure: "ConnectionAborted", }, { - Errno: "EALREADY", + Errno: "EALREADY", + Failure: "ConnectionAlreadyInProgress", }, { - Errno: "EDESTADDRREQ", + Errno: "EDESTADDRREQ", + Failure: "DestinationAddressRequired", }, { - Errno: "EINTR", + Errno: "EINTR", + Failure: "Interrupted", }, { - Errno: "EINVAL", + Errno: "EINVAL", + Failure: "InvalidArgument", }, { - Errno: "EMSGSIZE", + Errno: "EMSGSIZE", + Failure: "MessageSize", }, { - Errno: "ENETDOWN", + Errno: "ENETDOWN", + Failure: "NetworkDown", }, { - Errno: "ENETRESET", + Errno: "ENETRESET", + Failure: "NetworkReset", }, { - Errno: "ENETUNREACH", + Errno: "ENETUNREACH", + Failure: "NetworkUnreachable", }, { - Errno: "ENOBUFS", + Errno: "ENOBUFS", + Failure: "NoBufferSpace", }, { - Errno: "ENOPROTOOPT", + Errno: "ENOPROTOOPT", + Failure: "NoProtocolOption", }, { - Errno: "ENOTSOCK", + Errno: "ENOTSOCK", + Failure: "NotASocket", }, { - Errno: "ENOTCONN", + Errno: "ENOTCONN", + Failure: "NotConnected", }, { - Errno: "EWOULDBLOCK", + Errno: "EWOULDBLOCK", + Failure: "OperationWouldBlock", }, { - Errno: "EACCES", + Errno: "EACCES", + Failure: "PermissionDenied", }, { - Errno: "EPROTONOSUPPORT", + Errno: "EPROTONOSUPPORT", + Failure: "ProtocolNotSupported", }, { - Errno: "EPROTOTYPE", + Errno: "EPROTOTYPE", + Failure: "WrongProtocolType", }} func fileCreate(filename string) *os.File { @@ -143,6 +164,19 @@ func writeGenericFile() { fileWrite(filep, "\t\"errors\"\n") fileWrite(filep, "\t\"syscall\"\n") fileWrite(filep, ")\n\n") + + fileWrite(filep, "// This enumeration lists the syscall-derived failures defined at\n") + fileWrite(filep, "// https://github.com/ooni/spec/blob/master/data-formats/df-007-errors.md\n") + fileWrite(filep, "//\n") + fileWrite(filep, "// See also the enumeration at failures.go for the failures that\n") + fileWrite(filep, "// DO NOT derive from system call errors.\n") + fileWrite(filep, "const (\n") + for _, spec := range Specs { + filePrintf(filep, "\tFailure%s = \"%s\"\n", spec.Failure, + strcase.ToSnake(spec.Failure)) + } + fileWrite(filep, ")\n\n") + fileWrite(filep, "// toSyscallErr converts a syscall error to the\n") fileWrite(filep, "// proper OONI error. Returns the OONI error string\n") fileWrite(filep, "// on success, an empty string otherwise.\n") @@ -164,6 +198,40 @@ func writeGenericFile() { fileWrite(filep, "\t}\n") fileWrite(filep, "\treturn \"\"\n") fileWrite(filep, "}\n\n") + + fileClose(filep) + gofmt(filename) +} + +func writeGenericTestFile() { + filename := "errno_test.go" + filep := fileCreate(filename) + + fileWrite(filep, "// Code generated by go generate; DO NOT EDIT.\n") + filePrintf(filep, "// Generated: %+v\n\n", time.Now()) + fileWrite(filep, "package errorsx\n\n") + fileWrite(filep, "import (\n") + fileWrite(filep, "\t\"io\"\n") + fileWrite(filep, "\t\"syscall\"\n") + fileWrite(filep, "\t\"testing\"\n") + fileWrite(filep, ")\n\n") + + fileWrite(filep, "func TestToSyscallErr(t *testing.T) {\n") + fileWrite(filep, "\tif v := toSyscallErr(io.EOF); v != \"\" {\n") + fileWrite(filep, "\t\tt.Fatalf(\"expected empty string, got '%s'\", v)\n") + fileWrite(filep, "\t}\n") + + for _, spec := range Specs { + filePrintf(filep, "\tif v := toSyscallErr(%s); v != Failure%s {\n", spec.Errno, spec.Failure) + filePrintf(filep, "\t\tt.Fatalf(\"expected '%%s', got '%%s'\", Failure%s, v)\n", spec.Failure) + fileWrite(filep, "\t}\n") + } + + fileWrite(filep, "\tif v := toSyscallErr(syscall.Errno(0)); v != \"\" {\n") + fileWrite(filep, "\t\tt.Fatalf(\"expected empty string, got '%s'\", v)\n") + fileWrite(filep, "\t}\n") + fileWrite(filep, "}\n") + fileClose(filep) gofmt(filename) } @@ -172,4 +240,5 @@ func main() { writeSystemSpecificFile("unix") writeSystemSpecificFile("windows") writeGenericFile() + writeGenericTestFile() }