Skip to content

Commit

Permalink
feat: current value aware fakes, dynamic args, etc
Browse files Browse the repository at this point in the history
  • Loading branch information
mdshack committed Sep 23, 2023
1 parent 456fd65 commit c0ae67f
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 85 deletions.
4 changes: 2 additions & 2 deletions src/processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ func (p LineProcessor) processInsert(s string) string {
switch v := e.(type) {
case *sqlparser.Literal:
if processor == "table" {
v.Val = p.Provider.Get(dataType)
v.Val = p.Provider.Get(dataType, &v.Val)
} else {
if column == "attribute_id" {
attributeId = string(v.Val)
Expand All @@ -80,7 +80,7 @@ func (p LineProcessor) processInsert(s string) string {
}
}
if column == "value" && result {
v.Val = p.Provider.Get(dataType)
v.Val = p.Provider.Get(dataType, &v.Val)
}
if p.Mode == "map-eav" {
if column == "entity_type_id" {
Expand Down
4 changes: 2 additions & 2 deletions src/processor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ func NewTestProvider() *TestProvider {
return p
}

func (p TestProvider) Get(s string) string {
func (p TestProvider) Get(s string, currentValue *string) string {
return s
}

Expand Down Expand Up @@ -59,7 +59,7 @@ func TestProcessLine(t *testing.T) {
processor.ProcessLine(") ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COMMENT='Admin User Table'")
processor.ProcessLine("/*!40101 SET character_set_client = @saved_cs_client */;")

r2 := processor.ProcessLine("INSERT INTO `admin_user` (`firstname`) VALUES ('bob');")
r2 := processor.ProcessLine("INSERT INTO `admin_user` (`firstname`) VALUES ('bob'),('joe'),('steve');")
if strings.Contains(r2, "bob") {
t.Error("Got bob wanted no bob")
}
Expand Down
55 changes: 53 additions & 2 deletions src/provider.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package dbanon

import (
"regexp"
"strings"
"math/rand"
"syreclabs.com/go/faker"
"github.com/google/uuid"
Expand All @@ -15,10 +17,14 @@ func NewProvider() *Provider {
}

type ProviderInterface interface {
Get(fakeType string) string
Get(fakeType string, currentValue *string) string
}

func (p Provider) Get(fakeType string) string {
func (p Provider) Get(fakeType string, currentValue *string) string {
if (strings.HasPrefix(fakeType, "dynamic")) {
return p.processDynamicFake(fakeType, currentValue)
}

switch fakeType {
// Name
case "first_name":
Expand Down Expand Up @@ -95,4 +101,49 @@ func (p Provider) fakeJson() string {

func (p Provider) fakeQueryParams() string {
return "?fake=true"
}

func (p Provider) processDynamicFake(fakeType string, currentValue *string) string {
// strip dynamic from fakeType
fakeType = strings.ReplaceAll(fakeType, "dynamic.", "")

var args []string
args, fakeType = p.processDynamicArgs(fakeType)

switch fakeType {
case "email":
return p.dynamicEmail(currentValue, args)
}

logger := GetLogger()
logger.Error(fakeType + " does not match any known dynamic type")

return ""
}

func (p Provider) processDynamicArgs(fakeType string) ([]string, string) {
reg := regexp.MustCompile(`\((.*?)\)`)
args := string(reg.Find([]byte(fakeType)))

fakeType = strings.ReplaceAll(fakeType, args, "")

args = strings.TrimPrefix(args, "(")
args = strings.TrimSuffix(args, ")")

return strings.Split(args, ","), fakeType
}

func (p Provider) dynamicEmail(currentValue *string, args []string) string {
if len(args) < 1 || args[0] == "" {
return faker.Internet().Email()
}

// args[0] is email we wish to not fake
ignoreEmail := args[0]
val := *currentValue
if strings.HasSuffix(val, ignoreEmail) {
return val
}

return faker.Internet().Email()
}
112 changes: 33 additions & 79 deletions src/provider_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package dbanon

import (
"github.com/sirupsen/logrus/hooks/test"
"regexp"
"strconv"
"testing"
"time"
Expand All @@ -12,41 +11,22 @@ func TestGetForEtcCases(t *testing.T) {
testLogger, hook := test.NewNullLogger()
SetLogger(testLogger)

fakeEmail = func() string {
return "bob@example.com"
}
val := "test"

provider := NewProvider()
_ = provider.Get("unique_email")

r1 := provider.Get("unique_email")
if r1 != "1bob@example.com" {
t.Errorf("Got %s wanted 1bob@example.com", r1)
}

_ = provider.Get("faker.Whoops1")
if hook.LastEntry().Message != "Whoops1 is not a supported provider" {
_ = provider.Get("faker.Whoops1", &val)
if hook.LastEntry().Message != "faker.Whoops1 does not match any known type" {
t.Errorf("Unsupported provider not handled correctly")
}

_ = provider.Get("faker.Number().Whoops2()")
if hook.LastEntry().Message != "Whoops2() is not a valid method" {
_ = provider.Get("faker.Number().Whoops2()", &val)
if hook.LastEntry().Message != "faker.Number().Whoops2() does not match any known type" {
t.Errorf("Unsupported method not handled correctly")
}

_ = provider.Get("faker.Internet().Slug")
if hook.LastEntry().Message != "Could not identify arguments for Slug" {
t.Errorf("Malformed arguments not handled correctly")
}

_ = provider.Get("firstnaaaaame")
if hook.LastEntry().Message != "firstnaaaaame does not match any known type" {
t.Errorf("Unknown provider type not handled correctly")
}

to := time.Now()
from := to.AddDate(-40, 0, 0)
r11a := provider.Get("datetime")
r11a := provider.Get("datetime", &val)
r11Time, _ := time.Parse("2006-01-02 15:04:05", r11a)
if r11Time.Before(from) || r11Time.After(to) {
t.Errorf("%v not in expected range [%v, %v]", r11Time, from, to)
Expand All @@ -62,16 +42,13 @@ func TestGetForLengthBasedOptions(t *testing.T) {
isStr bool
}{
"md5": {input: "md5", wantGt: 31, wantLt: 33, isStr: true},
"note255": {input: "note255", wantGt: 49, wantLt: 51, isStr: true},
"region_id": {input: "region_id", wantGt: 0, wantLt: 551, isStr: false},
"faker.Number().Between(1, 550)": {input: "faker.Number().Between(1, 550)", wantGt: 0, wantLt: 551, isStr: false},
"gender": {input: "gender", wantGt: 0, wantLt: 4, isStr: false},
"shipment_tracking_number": {input: "shipment_tracking_number", wantGt: 17, wantLt: 19, isStr: true},
}

val := "test"

for name, tc := range tests {
t.Run(name, func(t *testing.T) {
got := provider.Get(tc.input)
got := provider.Get(tc.input, &val)
var compare int
if tc.isStr {
compare = len(got)
Expand All @@ -86,56 +63,33 @@ func TestGetForLengthBasedOptions(t *testing.T) {
}
}

func TestGetForSimpleRegexOptions(t *testing.T) {
func TestDynamicEmailProviderIgnoresEmail(t *testing.T) {
provider := NewProvider()

tests := map[string]struct {
input string
want string
}{
// https://github.com/dmgk/faker/blob/v1.2.3/internet_test.go#L63
"faker.Internet().Slug()": {input: "faker.Internet().Slug()", want: `\w+`},
// https://github.com/dmgk/faker/blob/v1.2.3/name_test.go#L10
"firstname": {input: "firstname", want: `[A-Z][a-z']+`},
"lastname": {input: "lastname", want: `[A-Z][a-z']+`},
"fullname": {input: "fullname", want: `[A-Z][a-z']+ [A-Z][a-z']+`},
// https://github.com/dmgk/faker/blob/v1.2.3/internet_test.go#L25
"username": {input: "username", want: `\w+`},
// https://github.com/dmgk/faker/blob/v1.2.3/internet_test.go#L9
"email": {input: "email", want: `\w+@\w+\.\w+`},
// https://github.com/dmgk/faker/blob/v1.2.3/internet_test.go#L9
"password": {input: "password", want: `\w+`},
// https://github.com/dmgk/faker/blob/v1.2.3/phone_number_test.go#L12
"telephone": {input: "telephone", want: `\w+`},
// https://github.com/dmgk/faker/blob/v1.2.3/address_test.go#L17
"street": {input: "street", want: `\d+\s[A-Z][a-z']+`},
// https://github.com/dmgk/faker/blob/v1.2.3/address_test.go#L30
"postcode": {input: "postcode", want: `[\d-]+`},
// // https://github.com/dmgk/faker/blob/v1.2.3/address_test.go#L10
"city": {input: "city", want: `[A-Z][a-z']+`},
// https://github.com/dmgk/faker/blob/v1.2.3/address_test.go#L60
"state": {input: "state", want: `\w+`},
// https://github.com/dmgk/faker/blob/v1.2.3/internet_test.go#L51
"ipv4": {input: "ipv4", want: `(\d{1,3}\.){3}\d{1,3}`},
// https://github.com/dmgk/faker/blob/v1.2.3/name_test.go#L22
"customer_suffix": {input: "customer_suffix", want: `[A-Z][a-z]*\.?`},
// https://github.com/dmgk/faker/blob/v1.2.3/name_test.go#L18
"title": {input: "title", want: `[A-Z][a-z]+\.?`},
// https://github.com/dmgk/faker/blob/v1.2.3/company_test.go#L10
"company": {input: "company", want: `[A-Z][a-z]+?`},
// https://github.com/dmgk/faker/blob/v1.2.3/lorem_test.go#L37-L46
"faker.Lorem().Sentence(3)": {input: "faker.Lorem().Sentence(3)", want: `[A-Z]\w*\s\w+\s\w+\.`},
// https://github.com/dmgk/faker/blob/v1.2.3/address_test.go#L72
"country_code": {input: "country_code", want: `\w+`},
"vat_number": {input: "vat_number", want: `GB[1-9][0-9]{8}`},
current := "blam@test.com"
value := provider.Get("dynamic.email(@test.com)", &current)
if current != value {
t.Errorf("new:%s does not equal original:%s when a fake was not expected", value, current)
}
}

for name, tc := range tests {
t.Run(name, func(t *testing.T) {
got := provider.Get(tc.input)
if m, _ := regexp.MatchString(tc.want, got); !m {
t.Errorf("Expected %v to match %v", got, tc.want)
}
})
func TestDynamicEmailProviderFakesEmail(t *testing.T) {
provider := NewProvider()

current := "blam@blam.com"
value := provider.Get("dynamic.email(@test.com)", &current)
if current == value {
t.Errorf("new:%s equals original:%s when a fake was expected", value, current)
}
}

func TestDynamicEmailProviderHandlesNoArgs(t *testing.T) {
provider := NewProvider()

current := "blam@blam.com"
faked1 := provider.Get("dynamic.email()", &current)
faked2 := provider.Get("dynamic.email", &current)
if faked1 == current || faked2 == current {
t.Error("unhandled empty args")
}
}

0 comments on commit c0ae67f

Please sign in to comment.