Skip to content

Commit 8751fe7

Browse files
Merge pull request #82 from warptools/normalize-regen
Normalize regen
2 parents 9d44a58 + 91ca5d1 commit 8751fe7

5 files changed

Lines changed: 119 additions & 18 deletions

File tree

app/testutil/guidmapper.go

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
package testutil
2+
3+
import (
4+
"log"
5+
"math/rand"
6+
"regexp"
7+
"strings"
8+
"sync"
9+
10+
"github.com/google/uuid"
11+
"github.com/icholy/replace"
12+
)
13+
14+
var reGuidJson = regexp.MustCompile(`"guid": "(?P<GUID>[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12})"`)
15+
16+
type GuidMapper struct {
17+
mapping map[string]string
18+
randSource rand.Source
19+
mappingMutex sync.Mutex
20+
}
21+
22+
func NewGuidMapper(r rand.Source) *GuidMapper {
23+
// Create a new source with a constant seed
24+
if r == nil {
25+
r = rand.NewSource(424242)
26+
}
27+
return &GuidMapper{
28+
mapping: make(map[string]string),
29+
randSource: r,
30+
}
31+
}
32+
33+
// Transformer returns a transform.Transformer for mapping GUIDs on streams
34+
func (gm *GuidMapper) Transformer() *replace.RegexpTransformer {
35+
return replace.RegexpStringSubmatchFunc(reGuidJson, gm.replacer)
36+
}
37+
38+
// get will return the mapping for the requested guid.
39+
// If the guid is unmapped, a new guid will be created.
40+
// GuidMapper uses a known random source so mapped guids should be deterministic
41+
// by order of requested guids.
42+
func (gm *GuidMapper) get(guid string) string {
43+
gm.mappingMutex.Lock()
44+
defer gm.mappingMutex.Unlock()
45+
if newGuid, exists := gm.mapping[guid]; exists {
46+
return newGuid
47+
}
48+
49+
// If the GUID is not in the mapping, generate a new one
50+
// Uses rand with a deterministic source so that a deterministic order is preserved.
51+
r := rand.New(gm.randSource)
52+
randBuf := make([]byte, 16)
53+
r.Read(randBuf)
54+
newGuid := uuid.NewSHA1(uuid.Nil, randBuf).String()
55+
gm.mapping[guid] = newGuid
56+
return newGuid
57+
}
58+
59+
// replacer implements the function for replace.RegexpStringSubmatchFunc.
60+
func (gm *GuidMapper) replacer(match []string) string {
61+
result := match[0]
62+
log.Println(match)
63+
for _, guid := range match[1:] {
64+
if _, err := uuid.Parse(guid); err != nil {
65+
continue
66+
}
67+
newGuid := gm.get(guid)
68+
result = strings.ReplaceAll(result, guid, newGuid)
69+
}
70+
log.Println(result)
71+
return result
72+
}

app/testutil/testutil.go

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,19 @@ import (
44
"bytes"
55
"errors"
66
"io"
7+
"math/rand"
78
"os"
89
"path/filepath"
910
"regexp"
1011
"strings"
1112
"testing"
1213

1314
qt "github.com/frankban/quicktest"
15+
"github.com/icholy/replace"
1416
"github.com/serum-errors/go-serum"
1517
"github.com/warpfork/go-testmark"
1618
"github.com/warpfork/go-testmark/testexec"
19+
"golang.org/x/text/transform"
1720

1821
wfapp "github.com/warptools/warpforge/app"
1922
"github.com/warptools/warpforge/pkg/testutil"
@@ -132,16 +135,6 @@ func cleanOutput(str string) string {
132135
// Also, it uses `os.Chdir` on this process (because we're "emulating a shell" rather than making subprocesses, whee).
133136
func buildExecFn(t *testing.T, projPath string) func([]string, io.Reader, io.Writer, io.Writer) (int, error) {
134137
return func(args []string, stdin io.Reader, stdout, stderr io.Writer) (int, error) {
135-
bufout, buferr := &bytes.Buffer{}, &bytes.Buffer{}
136-
var testout io.Writer = bufout
137-
if stdout != nil {
138-
testout = io.MultiWriter(stdout, bufout)
139-
}
140-
var testerr io.Writer = bufout
141-
if stderr != nil {
142-
testerr = io.MultiWriter(stderr, buferr)
143-
}
144-
145138
// override the path to required binaries
146139
pluginPath := filepath.Join(projPath, "plugins")
147140
err := os.Setenv("WARPFORGE_PATH", pluginPath)
@@ -171,10 +164,38 @@ func buildExecFn(t *testing.T, projPath string) func([]string, io.Reader, io.Wri
171164
// return nil
172165
// })
173166

167+
bufout, buferr := &bytes.Buffer{}, &bytes.Buffer{}
168+
var testout io.Writer = bufout
169+
170+
if stdout != nil {
171+
testout = io.MultiWriter(stdout, bufout)
172+
}
173+
// transform.NewWriter must call Close() to flush all output
174+
testout = transform.NewWriter(testout,
175+
transform.Chain(
176+
NewGuidMapper(rand.NewSource(65)).Transformer(),
177+
replace.RegexpString(regexp.MustCompile(`"time": [0-9]+`), `"time": 169455678`),
178+
),
179+
)
180+
181+
var testerr io.Writer = bufout
182+
if stderr != nil {
183+
testerr = io.MultiWriter(stderr, buferr)
184+
}
185+
// transform.NewWriter must call Close() to flush all output
186+
testerr = transform.NewWriter(testerr,
187+
transform.Chain(
188+
NewGuidMapper(rand.NewSource(66)).Transformer(),
189+
replace.RegexpString(regexp.MustCompile(`"time": [0-9]+`), `"time": 169455699`),
190+
),
191+
)
192+
174193
wfapp.App.Reader = stdin
175194
wfapp.App.Writer = testout
176195
wfapp.App.ErrWriter = testerr
177196
err = wfapp.App.Run(args)
197+
testout.(io.Closer).Close()
198+
testerr.(io.Closer).Close()
178199

179200
exitCode := 0
180201
if err != nil {

examples/500-cli/cli.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ The result of this will be a `RunRecord` object printed to stdout:
215215

216216
[testmark]:# (runformula/tags=net/stdout)
217217
```
218-
{ "runrecord": { "guid": "857b9774-e251-4bbc-9268-1883919fab23", "time": 1674646900, "formulaID": "zM5K3Zz8R3ioVVWZ6o6GocxPKvubAJfv4iQmDH3GCq9UjtDjHtRWrry4DRoEBPvfUEYFx1D", "exitcode": 0, "results": {} } }
218+
{ "runrecord": { "guid": "4a1d0896-f161-5fe8-87e5-d8fbb6d87368", "time": 169455678, "formulaID": "zM5K3Zz8R3ioVVWZ6o6GocxPKvubAJfv4iQmDH3GCq9UjtDjHtRWrry4DRoEBPvfUEYFx1D", "exitcode": 0, "results": {} } }
219219
```
220220

221221
(Note that we've normalized some of the values in this object for testing purposes.
@@ -358,10 +358,10 @@ there's only one record in this map.
358358

359359
[testmark]:# (base-workspace/then-runmodule/stdout)
360360
```
361-
{ "runrecord": { "guid": "c7fedecf-79b7-434b-9521-bf79a210cb2d", "time": 1692910078, "formulaID": "zM5K3RvfmKy9zLfHk1T6kPafmvzAGt9Ls1QYFS4BvWTaCBgxYoJLDkkqP7SD7QWuoRTYw3j", "exitcode": 0, "results": { "test": "ware:tar:2En3zD1ho1qNeLpPryZVM1UTGnqPvnt48WY36TzCGJwSCudxPXkDtN3UuS4J3AYWAM" } } }
362-
{ "runrecord": { "guid": "25f4a58b-2d45-4c01-b3ca-3d15165535a4", "time": 1692910079, "formulaID": "zM5K3Rqj146W38bBjgU8yeJ4i37YtydoZGvpsqaHbNE2akLWfDYp8vi2KAh7vvU3XdUoy12", "exitcode": 0, "results": { "test": "ware:tar:4tvpCNb1XJ3gkH25MREMPBHRWa7gLUiYt7pF6AHNbqgwBrs3btvvmijebyZrYsi6Y9" } } }
361+
{ "runrecord": { "guid": "4a1d0896-f161-5fe8-87e5-d8fbb6d87368", "time": 169455678, "formulaID": "zM5K3RvfmKy9zLfHk1T6kPafmvzAGt9Ls1QYFS4BvWTaCBgxYoJLDkkqP7SD7QWuoRTYw3j", "exitcode": 0, "results": { "test": "ware:tar:2En3zD1ho1qNeLpPryZVM1UTGnqPvnt48WY36TzCGJwSCudxPXkDtN3UuS4J3AYWAM" } } }
362+
{ "runrecord": { "guid": "423d9dfb-ea0b-51eb-8cbd-7bf6f198e25b", "time": 169455678, "formulaID": "zM5K3Rqj146W38bBjgU8yeJ4i37YtydoZGvpsqaHbNE2akLWfDYp8vi2KAh7vvU3XdUoy12", "exitcode": 0, "results": { "test": "ware:tar:4tvpCNb1XJ3gkH25MREMPBHRWa7gLUiYt7pF6AHNbqgwBrs3btvvmijebyZrYsi6Y9" } } }
363363
{ "plotresults": { "test": "tar:4tvpCNb1XJ3gkH25MREMPBHRWa7gLUiYt7pF6AHNbqgwBrs3btvvmijebyZrYsi6Y9" } }
364-
{ "runrecord": { "guid": "df7923fd-1ff6-4600-8984-f896d79610fd", "time": 1692910079, "formulaID": "zM5K3T8946y1A7Z4ZEuoCizPdDuneUQMqXqyfxXSh93CtK3n6gzgJgz9PMTUzJiexPErUqM", "exitcode": 0, "results": {} } }
364+
{ "runrecord": { "guid": "24658cf3-ee69-588f-a86a-40d1ef2b9a34", "time": 169455678, "formulaID": "zM5K3T8946y1A7Z4ZEuoCizPdDuneUQMqXqyfxXSh93CtK3n6gzgJgz9PMTUzJiexPErUqM", "exitcode": 0, "results": {} } }
365365
{ "plotresults": { "test": "tar:4tvpCNb1XJ3gkH25MREMPBHRWa7gLUiYt7pF6AHNbqgwBrs3btvvmijebyZrYsi6Y9" } }
366366
```
367367

@@ -627,7 +627,7 @@ Check that `ferk` ran successfully, no outputs are expected.
627627

628628
[testmark]:# (base-workspace/then-ferk/stdout)
629629
```
630-
{ "runrecord": { "guid": "61940b67-024a-476e-996e-740ff80356c7", "time": 1692910079, "formulaID": "zM5K3V1fXVjExjfVd8d7ByUQ7HP16QAcZcoRd1bh3X4uvms1Xbpb87c1a7WNaw8Hw2B3uF6", "exitcode": 0, "results": { "out": "ware:tar:-" } } }
630+
{ "runrecord": { "guid": "4a1d0896-f161-5fe8-87e5-d8fbb6d87368", "time": 169455678, "formulaID": "zM5K3V1fXVjExjfVd8d7ByUQ7HP16QAcZcoRd1bh3X4uvms1Xbpb87c1a7WNaw8Hw2B3uF6", "exitcode": 0, "results": { "out": "ware:tar:-" } } }
631631
{ "plotresults": { "out": "tar:-" } }
632632
```
633633

@@ -671,7 +671,7 @@ warpforge --json --quiet ferk --plot ./plot.wf --cmd /bin/echo --no-interactive
671671

672672
[testmark]:# (base-workspace/then-ferk-with-plot/stdout)
673673
```
674-
{ "runrecord": { "guid": "b964aa2f-bb7a-44c4-b4fa-bfc9d15d0ace", "time": 1692910079, "formulaID": "zM5K3YWRYqSgvxgMkAA9KbzPpqtRPbufF2z397SNJ1mKTkp9SpmxA8jD3YmTPu3EWvijMSv", "exitcode": 0, "results": {} } }
674+
{ "runrecord": { "guid": "4a1d0896-f161-5fe8-87e5-d8fbb6d87368", "time": 169455678, "formulaID": "zM5K3YWRYqSgvxgMkAA9KbzPpqtRPbufF2z397SNJ1mKTkp9SpmxA8jD3YmTPu3EWvijMSv", "exitcode": 0, "results": {} } }
675675
{ "plotresults": {} }
676676
```
677677

@@ -710,7 +710,7 @@ warpforge --json run
710710
{ "log": { "Msg": "ware mount: wareId = tar:4z9DCTxoKkStqXQRwtf9nimpfQQ36dbndDsAPCQgECfbXt3edanUrsVKCjE9TkX2v9 destPath = /" } }
711711
{ "log": { "Msg": "executing script interpreter = /bin/sh" } }
712712
{ "log": { "Msg": "packed \"out\": path = /output wareId=tar:6U2WhgnXRCLsNjZLyvLzG6Eer5MH4MpguDeimPrEafHytjmXjbvxjm1STCuqHV5AQA" } }
713-
{ "runrecord": { "guid": "6785b641-6e41-4ecb-9207-4ecd60b85bd6", "time": 1692910079, "formulaID": "zM5K3ZMzLiBwQB93yZ4nFUsVSSgVtNPjpY72hKHxDjc9FRk9KnJSoCvkHFEPWfxARdjaguZ", "exitcode": 0, "results": { "out": "ware:tar:6U2WhgnXRCLsNjZLyvLzG6Eer5MH4MpguDeimPrEafHytjmXjbvxjm1STCuqHV5AQA" } } }
713+
{ "runrecord": { "guid": "4a1d0896-f161-5fe8-87e5-d8fbb6d87368", "time": 169455678, "formulaID": "zM5K3ZMzLiBwQB93yZ4nFUsVSSgVtNPjpY72hKHxDjc9FRk9KnJSoCvkHFEPWfxARdjaguZ", "exitcode": 0, "results": { "out": "ware:tar:6U2WhgnXRCLsNjZLyvLzG6Eer5MH4MpguDeimPrEafHytjmXjbvxjm1STCuqHV5AQA" } } }
714714
{ "log": { "Msg": "(hello-world) collected output hello-world:out" } }
715715
{ "log": { "Msg": "(hello-world) complete" } }
716716
{ "plotresults": { "output": "tar:6U2WhgnXRCLsNjZLyvLzG6Eer5MH4MpguDeimPrEafHytjmXjbvxjm1STCuqHV5AQA" } }

go.mod

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ require (
1414
github.com/frankban/quicktest v1.14.5
1515
github.com/go-git/go-git/v5 v5.6.1
1616
github.com/google/uuid v1.3.0
17+
github.com/icholy/replace v0.6.0
1718
github.com/ipfs/go-cid v0.4.1
1819
github.com/ipld/go-ipld-prime v0.20.0
1920
github.com/opencontainers/runtime-spec v1.0.2
@@ -96,7 +97,7 @@ require (
9697
golang.org/x/mod v0.10.0 // indirect
9798
golang.org/x/net v0.9.0 // indirect
9899
golang.org/x/term v0.8.0
99-
golang.org/x/text v0.9.0 // indirect
100+
golang.org/x/text v0.9.0
100101
golang.org/x/tools v0.8.0 // indirect
101102
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect
102103
google.golang.org/grpc v1.54.0 // indirect

go.sum

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,8 @@ github.com/grpc-ecosystem/grpc-gateway/v2 v2.15.2/go.mod h1:7pdNwVWBBHGiCxa9lAsz
224224
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
225225
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
226226
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
227+
github.com/icholy/replace v0.6.0 h1:EBiD2pGqZIOJAbEaf/5GVRaD/Pmbb4n+K3LrBdXd4dw=
228+
github.com/icholy/replace v0.6.0/go.mod h1:zzi8pxElj2t/5wHHHYmH45D+KxytX/t4w3ClY5nlK+g=
227229
github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg=
228230
github.com/imdario/mergo v0.3.15 h1:M8XP7IuFNsqUx6VPK2P9OSmsYsI/YFaGil0uD21V3dM=
229231
github.com/imdario/mergo v0.3.15/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=
@@ -291,6 +293,7 @@ github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/
291293
github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4=
292294
github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI=
293295
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
296+
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
294297
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
295298
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
296299
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
@@ -325,6 +328,7 @@ github.com/smartystreets/goconvey v1.7.2/go.mod h1:Vw0tHAZW6lzCRk3xgdin6fKYcG+G3
325328
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
326329
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
327330
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
331+
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
328332
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
329333
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
330334
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
@@ -560,6 +564,7 @@ golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBn
560564
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
561565
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
562566
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
567+
golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
563568
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
564569
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
565570
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
@@ -705,6 +710,8 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C
705710
gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
706711
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
707712
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
713+
gotest.tools/v3 v3.0.2 h1:kG1BFyqVHuQoVQiR1bWGnfz/fmHvvuiSPIV7rvl360E=
714+
gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
708715
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
709716
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
710717
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

0 commit comments

Comments
 (0)