Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update fuzz tests to use go fuzz features #148

Merged
merged 14 commits into from
Jun 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 0 additions & 5 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,6 @@ jobs:
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support

steps:
- name: Harden Runner
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Removed harden in places that I missed it.

uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1
with:
egress-policy: audit

- name: Checkout repository
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7

Expand Down
5 changes: 0 additions & 5 deletions .github/workflows/dependency-review.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,6 @@ jobs:
dependency-review:
runs-on: ubuntu-latest
steps:
- name: Harden Runner
uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1
with:
egress-policy: audit

- name: 'Checkout Repository'
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
- name: 'Dependency Review'
Expand Down
16 changes: 3 additions & 13 deletions .github/workflows/go.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,6 @@ jobs:
env:
GO111MODULE: auto
steps:

- name: Harden Runner
uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1
with:
egress-policy: audit

- name: Build
uses: actions/setup-go@cdcb36043654635271a94b9a6d1392de5bb323a7 # v5.0.1
with:
Expand All @@ -38,20 +32,16 @@ jobs:
run: go test ./... -race -coverprofile=coverage.txt -covermode=atomic

- name: Coverage
uses: codecov/codecov-action@125fc84a9a348dbcf27191600683ec096ec9021c # v4.4.1
uses: codecov/codecov-action@e28ff129e5465c2c0dcc6f003fc735cb6ae0c673 # v4.5.0
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}

build-legacy:
name: Build + Test Previous Stable
runs-on: ubuntu-latest
env:
GO111MODULE: auto
steps:

- name: Harden Runner
uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1
with:
egress-policy: audit

- name: Build
uses: actions/setup-go@cdcb36043654635271a94b9a6d1392de5bb323a7 # v5.0.1
with:
Expand Down
121 changes: 100 additions & 21 deletions codec_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,7 @@ package uuid

import (
"bytes"
"flag"
"fmt"
"os"
"path/filepath"
"regexp"
"strings"
"testing"
)
Expand Down Expand Up @@ -403,28 +400,110 @@ func BenchmarkParseV4(b *testing.B) {
}
}

var seedFuzzCorpus = flag.Bool("seed_fuzz_corpus", false, "seed fuzz test corpus")
const uuidPattern = "[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}"

func TestSeedFuzzCorpus(t *testing.T) {
// flag.Parse() is called for us by the test binary.
if !*seedFuzzCorpus {
t.Skip("seeding fuzz test corpus only on demand")
var fromBytesCorpus = [][]byte{
{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8},
{4, 8, 15, 16, 23, 42},
}

// FuzzFromBytesFunc is a fuzz testing suite that exercises the FromBytes function
func FuzzFromBytesFunc(f *testing.F) {
for _, seed := range fromBytesCorpus {
f.Add(seed)
}
corpusDir := filepath.Join(".", "testdata", "corpus")
writeSeedFile := func(name, data string) error {
path := filepath.Join(corpusDir, name)
return os.WriteFile(path, []byte(data), os.ModePerm)
uuidRegexp, err := regexp.Compile(uuidPattern)
if err != nil {
f.Fatal("uuid regexp failed to compile")
}
for _, fst := range fromStringTests {
name := "seed_valid_" + fst.variant
if err := writeSeedFile(name, fst.input); err != nil {
t.Fatal(err)
f.Fuzz(func(t *testing.T, payload []byte) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

the general logic for this pair is that if the payload was not 16 bytes, we fail the fuzz if fan error was not returned (or put another way, we verify that the function returns an error when the payload is 16 bytes). Otherwise, if an error was not returned, we make sure it's not a Nil uuid, and we make sure it matched the uuid pattern

u, err := FromBytes(payload)
if len(payload) != Size && err == nil {
t.Errorf("%v did not result in an error", payload)
}
if len(payload) == Size && u == Nil {
t.Errorf("%v resulted in Nil uuid", payload)
}
if len(payload) == Size && !uuidRegexp.MatchString(u.String()) {
dylan-bourque marked this conversation as resolved.
Show resolved Hide resolved
t.Errorf("%v resulted in invalid uuid %s", payload, u.String())
}
// otherwise, allow to pass if no panic
})
}

// FuzzFromBytesOrNilFunc is a fuzz testing suite that exercises the FromBytesOrNil function
func FuzzFromBytesOrNilFunc(f *testing.F) {
for _, seed := range fromBytesCorpus {
f.Add(seed)
}
for i, s := range invalidFromStringInputs {
name := fmt.Sprintf("seed_invalid_%d", i)
if err := writeSeedFile(name, s); err != nil {
t.Fatal(err)
uuidRegexp, err := regexp.Compile(uuidPattern)
if err != nil {
f.Error("uuid regexp failed to compile")
}
f.Fuzz(func(t *testing.T, payload []byte) {
u := FromBytesOrNil(payload)
if len(payload) != Size && u != Nil {
t.Errorf("%v resulted in non Nil uuid %s", payload, u.String())
}
if len(payload) == Size && u == Nil {
t.Errorf("%v resulted Nil uuid", payload)
}
if len(payload) == Size && !uuidRegexp.MatchString(u.String()) {
t.Errorf("%v resulted in invalid uuid %s", payload, u.String())
}
// otherwise, allow to pass if no panic
})
}

var fromStringCorpus = []string{
"6ba7b810-9dad-11d1-80b4-00c04fd430c8",
"6BA7B810-9DAD-11D1-80B4-00C04FD430C8",
"{6BA7B810-9DAD-11D1-80B4-00C04FD430C8}",
"urn:uuid:6BA7B810-9DAD-11D1-80B4-00C04FD430C8",
"6BA7B8109DAD11D180B400C04FD430C8",
"{6BA7B8109DAD11D180B400C04FD430C8}",
"urn:uuid:6BA7B8109DAD11D180B400C04FD430C8",
}

// FuzzFromStringFunc is a fuzz testing suite that exercises the FromString function
func FuzzFromStringFunc(f *testing.F) {
for _, seed := range fromStringCorpus {
f.Add(seed)
}
uuidRegexp, err := regexp.Compile(uuidPattern)
if err != nil {
f.Fatal("uuid regexp failed to compile")
}
f.Fuzz(func(t *testing.T, payload string) {
u, err := FromString(payload)
if err != nil {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

the general logic for this pair is that if the function didn't return an error, we make sure the uuid matches a regex for uuids. Otherwise, we assume the error was correct for the input. This implicitly fails the fuzz test on a panic.

if u == Nil {
t.Errorf("%s resulted in Nil uuid", payload)
}
if !uuidRegexp.MatchString(u.String()) {
t.Errorf("%s resulted in invalid uuid %s", payload, u.String())
}
}
// otherwise, allow to pass if no panic
})
}

// FuzzFromStringOrNil is a fuzz testing suite that exercises the FromStringOrNil function
func FuzzFromStringOrNilFunc(f *testing.F) {
for _, seed := range fromStringCorpus {
f.Add(seed)
}
uuidRegexp, err := regexp.Compile(uuidPattern)
if err != nil {
f.Error("uuid regexp failed to compile")
}
f.Fuzz(func(t *testing.T, payload string) {
u := FromStringOrNil(payload)
if u != Nil {
if !uuidRegexp.MatchString(u.String()) {
t.Errorf("%s resulted in invalid uuid %s", payload, u.String())
}
}
// otherwise, allow to pass if no panic
})
}
48 changes: 0 additions & 48 deletions fuzz.go

This file was deleted.

1 change: 1 addition & 0 deletions generator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -611,6 +611,7 @@ func testNewV7(t *testing.T) {
t.Run("FaultyRand", makeTestNewV7FaultyRand())
t.Run("FaultyRandWithOptions", makeTestNewV7FaultyRandWithOptions())
t.Run("ShortRandomRead", makeTestNewV7ShortRandomRead())
t.Run("ShortRandomReadWithOptions", makeTestNewV7ShortRandomReadWithOptions())
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

While I was here I noticed that one of the v7 test functions weren't being run, so I added it here.

t.Run("KSortable", makeTestNewV7KSortable())
t.Run("ClockSequence", makeTestNewV7ClockSequence())
}
Expand Down
1 change: 0 additions & 1 deletion testdata/corpus/1416586f4a34d02bcb506f6107b40df512b9f2f9

This file was deleted.

1 change: 0 additions & 1 deletion testdata/corpus/3b46a7e7b02ec193581e6c9fa2c8a72f50a64e08-1

This file was deleted.

1 change: 0 additions & 1 deletion testdata/corpus/50c54bb75fcfdc488f162bf2f0c6dec6103bfa18-5

This file was deleted.

1 change: 0 additions & 1 deletion testdata/corpus/69c581ab749cbd56be8684d3a58ac2cfab9af0f4-5

This file was deleted.

1 change: 0 additions & 1 deletion testdata/corpus/752bf000e0bff06777dd0d6f0be6353844de678a-3

This file was deleted.

1 change: 0 additions & 1 deletion testdata/corpus/a4483762d4ece8466d82cca5cacd35a0829c4e60-2

This file was deleted.

1 change: 0 additions & 1 deletion testdata/corpus/d0952c45e0c823fc5cc12bcf7d9b877d150ab523-1

This file was deleted.

Empty file.
1 change: 0 additions & 1 deletion testdata/corpus/e2b84d2065846891f18ae109b12e01d224e1c7c3-4

This file was deleted.

1 change: 0 additions & 1 deletion testdata/corpus/e320d749435115e874f77420e17d0937e07f69f3-2

This file was deleted.

1 change: 0 additions & 1 deletion testdata/corpus/ed132d47d757f6468443a22df8a2a965efb34098-7

This file was deleted.

1 change: 0 additions & 1 deletion testdata/corpus/eeefb01f7bb3c627aedb292c994b20f739ffd613-6

This file was deleted.

1 change: 0 additions & 1 deletion testdata/corpus/seed_invalid_0

This file was deleted.

1 change: 0 additions & 1 deletion testdata/corpus/seed_invalid_1

This file was deleted.

1 change: 0 additions & 1 deletion testdata/corpus/seed_invalid_10

This file was deleted.

1 change: 0 additions & 1 deletion testdata/corpus/seed_invalid_11

This file was deleted.

1 change: 0 additions & 1 deletion testdata/corpus/seed_invalid_12

This file was deleted.

1 change: 0 additions & 1 deletion testdata/corpus/seed_invalid_13

This file was deleted.

1 change: 0 additions & 1 deletion testdata/corpus/seed_invalid_14

This file was deleted.

1 change: 0 additions & 1 deletion testdata/corpus/seed_invalid_15

This file was deleted.

1 change: 0 additions & 1 deletion testdata/corpus/seed_invalid_16

This file was deleted.

1 change: 0 additions & 1 deletion testdata/corpus/seed_invalid_17

This file was deleted.

1 change: 0 additions & 1 deletion testdata/corpus/seed_invalid_18

This file was deleted.

1 change: 0 additions & 1 deletion testdata/corpus/seed_invalid_19

This file was deleted.

1 change: 0 additions & 1 deletion testdata/corpus/seed_invalid_2

This file was deleted.

1 change: 0 additions & 1 deletion testdata/corpus/seed_invalid_20

This file was deleted.

1 change: 0 additions & 1 deletion testdata/corpus/seed_invalid_21

This file was deleted.

1 change: 0 additions & 1 deletion testdata/corpus/seed_invalid_22

This file was deleted.

1 change: 0 additions & 1 deletion testdata/corpus/seed_invalid_23

This file was deleted.

1 change: 0 additions & 1 deletion testdata/corpus/seed_invalid_3

This file was deleted.

1 change: 0 additions & 1 deletion testdata/corpus/seed_invalid_4

This file was deleted.

1 change: 0 additions & 1 deletion testdata/corpus/seed_invalid_5

This file was deleted.

1 change: 0 additions & 1 deletion testdata/corpus/seed_invalid_6

This file was deleted.

1 change: 0 additions & 1 deletion testdata/corpus/seed_invalid_7

This file was deleted.

1 change: 0 additions & 1 deletion testdata/corpus/seed_invalid_8

This file was deleted.

1 change: 0 additions & 1 deletion testdata/corpus/seed_invalid_9

This file was deleted.

1 change: 0 additions & 1 deletion testdata/corpus/seed_valid_BracedCanonical

This file was deleted.

1 change: 0 additions & 1 deletion testdata/corpus/seed_valid_BracedHashlike

This file was deleted.

1 change: 0 additions & 1 deletion testdata/corpus/seed_valid_Canonical

This file was deleted.

1 change: 0 additions & 1 deletion testdata/corpus/seed_valid_Hashlike

This file was deleted.

1 change: 0 additions & 1 deletion testdata/corpus/seed_valid_URNCanonical

This file was deleted.

1 change: 0 additions & 1 deletion testdata/corpus/seed_valid_URNHashlike

This file was deleted.

Loading