Skip to content

Commit

Permalink
feat(timeline): add initial state setup (#295)
Browse files Browse the repository at this point in the history
* feat(timeline): add initial state setup

* feat(timeline): add venom test
  • Loading branch information
adrienaury authored Apr 10, 2024
1 parent 1b6d7f6 commit 9317083
Show file tree
Hide file tree
Showing 4 changed files with 123 additions and 3 deletions.
14 changes: 12 additions & 2 deletions pkg/axis/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,17 +72,19 @@ func (g *Generator) SetPoint(name string, reference string, min, max int64, defa
})
}

func (g *Generator) Generate(rng *rand.Rand) (map[string]*int64, error) {
func (g *Generator) Generate(rng *rand.Rand, initialStates ...map[string]*int64) (map[string]*int64, error) {
loopCount := 0

Loop:
for {
loopCount++

result := make(map[string]*int64, len(g.points)+1)
result := make(map[string]*int64, len(g.points)*2+1)

result[g.originName] = &g.originValue

loadStates(result, initialStates)

for _, point := range g.points {
var pointer *int64

Expand Down Expand Up @@ -124,3 +126,11 @@ Loop:
func (g *Generator) Origin() string {
return g.originName
}

func loadStates(target map[string]*int64, states []map[string]*int64) {
for _, state := range states {
for name, value := range state {
target[name] = value
}
}
}
38 changes: 38 additions & 0 deletions pkg/axis/generate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ import (
)

func TestSimple(t *testing.T) {
t.Parallel()

generator := axis.NewGenerator("start", 0)

generator.SetPoint("birth", "start", -80, -18, "")
Expand All @@ -47,3 +49,39 @@ func TestSimple(t *testing.T) {

assert.Len(t, result, 4)
}

func TestInitialState(t *testing.T) {
t.Parallel()

generator := axis.NewGenerator("start", 0)

generator.SetPoint("birth", "birth", 0, 20, "")
generator.SetPoint("contract", "contract", -5, 5, "", axis.GreaterThan("birth", axis.Nullify))
generator.SetPoint("promotion", "promotion", -5, 5, "", axis.GreaterThan("contract", axis.Nullify))

generator.SetMaxRetry(1)

birth := int64(0)
contract := int64(25)
promotion := int64(27)

state := map[string]*int64{
"birth": &birth,
"contract": &contract,
"promotion": &promotion,
}

result, err := generator.Generate(rand.New(rand.NewSource(8)), state) //nolint:gosec

require.NoError(t, err)

for key, value := range result {
if value != nil {
println(key, *value)
} else {
println(key, "nil")
}
}

assert.Len(t, result, 4)
}
31 changes: 30 additions & 1 deletion pkg/timeline/timeline.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,20 @@ func (me MaskEngine) Mask(e model.Entry, context ...model.Dictionary) (model.Ent
}
}

timestamps, err := me.Generate(me.rand)
initialState := map[string]*int64{}
if dict, ok := e.(model.Dictionary); ok {
iter := dict.EntriesIter()
for {
pair, ok := iter()
if !ok {
break
}

initialState[pair.Key] = me.formatTimestamp(pair.Value)
}
}

timestamps, err := me.Generate(me.rand, initialState)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -160,6 +173,22 @@ func (me MaskEngine) formatDate(timestamp int64) model.Entry {
return time.Unix(timestamp, 0).Format(time.RFC3339)
}

func (me MaskEngine) formatTimestamp(date model.Entry) *int64 {
switch typedDate := date.(type) {
case nil:
return nil
case string:
t, err := time.Parse(me.format, typedDate)
if err != nil {
return nil
}
timestamp := t.Unix()
return &timestamp
default:
return nil
}
}

func durationToSeconds(iso8601 string) (int64, error) {
dur, err := duration.ParseDuration(iso8601)
if err != nil {
Expand Down
43 changes: 43 additions & 0 deletions test/suites/masking_timeline.yml
Original file line number Diff line number Diff line change
Expand Up @@ -246,3 +246,46 @@ testcases:
- result.code ShouldEqual 4
- |
result.systemerr ShouldContainSubstring rejected timeline generation, can't find a value that satisfy constraint: contract
- name: pre-existing date can be used as constraints and as reference from
steps:
- script: rm -f masking.yml
- script: |-
cat > masking.yml <<EOF
version: "1"
seed: 42
masking:
- selector:
jsonpath: "timeline"
masks:
- timeline:
start:
name: "today"
value: "2006-01-02T15:04:05Z"
format: "2006-01-02"
retry: 0
points:
- name: "birth"
from: "birth"
min: "-P1Y"
max: "+P1Y"
- name: "contract"
from: "contract"
min: "-P1Y"
max: "+P1Y"
constraints:
- after: "birth"
- name: "promotion"
from: "promotion"
min: "-P1Y"
max: "+P1Y"
constraints:
- after: "contract"
EOF
- script: echo '{"timeline":{"birth":"1984-06-09","contract":"2007-01-02","promotion":"2007-10-26"}}' | pimo
assertions:
- result.code ShouldEqual 0
- result.systemoutjson.timeline.birth ShouldEqual "1984-05-01"
- result.systemoutjson.timeline.contract ShouldEqual "2007-08-24"
- result.systemoutjson.timeline.promotion ShouldBeEmpty # is empty because the constraint failed
- result.systemerr ShouldBeEmpty

0 comments on commit 9317083

Please sign in to comment.