Skip to content

Commit 05a1b4a

Browse files
stephenmcconkeyDave Johnston
authored and
Dave Johnston
committed
FFM-4043 - Add checks for nested pre req flags (harness#95)
* Change 'number' to 'int' input on number variations * Check prereq flags for nested prereqs, update example app * simple refactor
1 parent 31be926 commit 05a1b4a

File tree

3 files changed

+238
-5
lines changed

3 files changed

+238
-5
lines changed

evaluation/feature.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,13 @@ func prereqsSatisfied(fc FeatureConfig, target *Target, flags map[string]Feature
304304
continue
305305
}
306306

307+
if prereqFlag.Prerequisites != nil {
308+
res := checkPreReqsForPreReqs(prereqFlag.Prerequisites, flags, target)
309+
if !res {
310+
return false
311+
}
312+
}
313+
307314
variationToMatch := prereqFlag.Variations.FindByIdentifier(prereqFlag.GetVariationName(target))
308315

309316
if pre.Feature == prereqFlag.Feature {
@@ -540,3 +547,29 @@ type WeightedVariation struct {
540547
Variation string
541548
Weight int
542549
}
550+
551+
func checkPreReqsForPreReqs(preReqFlagPreReqs []Prerequisite, flags map[string]FeatureConfig, target *Target) bool {
552+
for _, preReq := range preReqFlagPreReqs {
553+
nestedPreReq, ok := flags[preReq.Feature]
554+
if !ok {
555+
continue
556+
}
557+
558+
if len(nestedPreReq.Prerequisites) > 0 {
559+
nested := checkPreReqsForPreReqs(nestedPreReq.Prerequisites, flags, target)
560+
if !nested {
561+
return false
562+
}
563+
}
564+
565+
preReqVariationToMatch := nestedPreReq.Variations.FindByIdentifier(nestedPreReq.GetVariationName(target))
566+
if preReq.Feature == nestedPreReq.Feature {
567+
for _, variation := range preReq.Variations {
568+
if variation != preReqVariationToMatch.Value {
569+
return false
570+
}
571+
}
572+
}
573+
}
574+
return true
575+
}

evaluation/feature_test.go

Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1546,3 +1546,203 @@ func TestFeatureConfig_prereqsSatisfied(t *testing.T) {
15461546
})
15471547
}
15481548
}
1549+
1550+
func TestCheckPreReqsForPreReqs(t *testing.T) {
1551+
trueVariation := Variation{
1552+
Name: stringPtr("True"),
1553+
Value: "true",
1554+
Identifier: "true",
1555+
}
1556+
1557+
falseVariation := Variation{
1558+
Name: stringPtr("False"),
1559+
Value: "false",
1560+
Identifier: "false",
1561+
}
1562+
1563+
blueVariation := Variation{
1564+
Name: stringPtr("blue"),
1565+
Value: "blue",
1566+
Identifier: "blue",
1567+
}
1568+
1569+
redVariation := Variation{
1570+
Name: stringPtr("red"),
1571+
Value: "red",
1572+
Identifier: "red",
1573+
}
1574+
1575+
flags := map[string]FeatureConfig{
1576+
"flag1": {
1577+
DefaultServe: Serve{
1578+
Variation: stringPtr("true"),
1579+
},
1580+
Environment: "dev",
1581+
Feature: "flag1",
1582+
Kind: "boolean",
1583+
OffVariation: "false",
1584+
Prerequisites: nil,
1585+
Project: "default",
1586+
Rules: nil,
1587+
State: "on",
1588+
VariationToTargetMap: nil,
1589+
Variations: Variations{
1590+
trueVariation, falseVariation,
1591+
},
1592+
Segments: nil,
1593+
},
1594+
"flag2": {
1595+
DefaultServe: Serve{
1596+
Variation: stringPtr("true"),
1597+
},
1598+
Environment: "dev",
1599+
Feature: "flag2",
1600+
Kind: "boolean",
1601+
OffVariation: "false",
1602+
Prerequisites: []Prerequisite{
1603+
{Feature: "flag1",
1604+
Variations: []string{"true"},
1605+
},
1606+
},
1607+
Project: "default",
1608+
Rules: nil,
1609+
State: "on",
1610+
VariationToTargetMap: nil,
1611+
Variations: Variations{
1612+
trueVariation, falseVariation,
1613+
},
1614+
Segments: nil,
1615+
},
1616+
"flag3": {
1617+
DefaultServe: Serve{
1618+
Variation: stringPtr("true"),
1619+
},
1620+
Environment: "dev",
1621+
Feature: "flag3",
1622+
Kind: "boolean",
1623+
OffVariation: "false",
1624+
Prerequisites: []Prerequisite{
1625+
{Feature: "flag2",
1626+
Variations: []string{"true"},
1627+
},
1628+
},
1629+
Project: "default",
1630+
Rules: nil,
1631+
State: "on",
1632+
VariationToTargetMap: nil,
1633+
Variations: Variations{
1634+
trueVariation, falseVariation,
1635+
},
1636+
Segments: nil,
1637+
},
1638+
"mv1": {
1639+
DefaultServe: Serve{
1640+
Variation: stringPtr("red"),
1641+
},
1642+
Environment: "dev",
1643+
Feature: "mv1",
1644+
Kind: "string",
1645+
OffVariation: "blue",
1646+
Prerequisites: []Prerequisite{
1647+
{Feature: "flag1",
1648+
Variations: []string{"true"},
1649+
},
1650+
},
1651+
Project: "default",
1652+
Rules: nil,
1653+
State: "on",
1654+
VariationToTargetMap: nil,
1655+
Variations: Variations{
1656+
redVariation, blueVariation,
1657+
},
1658+
Segments: nil,
1659+
},
1660+
}
1661+
tests := []struct {
1662+
name string
1663+
expected bool
1664+
preReqFlagPreReqs []Prerequisite
1665+
flags map[string]FeatureConfig
1666+
target *Target
1667+
}{
1668+
{
1669+
name: "Given I have no preReqFlagPreReqs",
1670+
expected: true,
1671+
flags: nil,
1672+
preReqFlagPreReqs: nil,
1673+
target: nil,
1674+
},
1675+
{
1676+
name: "Given I have a preReqFlagPreReqs that has no nested preregs that will match",
1677+
expected: true,
1678+
flags: flags,
1679+
preReqFlagPreReqs: []Prerequisite{
1680+
{Feature: "flag1",
1681+
Variations: []string{"true"},
1682+
},
1683+
},
1684+
target: nil,
1685+
},
1686+
{
1687+
name: "Given I have a preReqFlagPreReqs that has no nested prereqs that will not match",
1688+
expected: false,
1689+
flags: flags,
1690+
preReqFlagPreReqs: []Prerequisite{
1691+
{Feature: "flag1",
1692+
Variations: []string{"false"},
1693+
},
1694+
},
1695+
target: nil,
1696+
},
1697+
{
1698+
name: "Given I have a preReqFlagPreReqs that has nested prereqs that will match i.e. flag 3 depends on flag 2, which depends on flag 1",
1699+
expected: true,
1700+
flags: flags,
1701+
preReqFlagPreReqs: []Prerequisite{
1702+
{Feature: "flag3",
1703+
Variations: []string{"true"},
1704+
},
1705+
},
1706+
target: nil,
1707+
},
1708+
{
1709+
name: "Given I have a preReqFlagPreReqs that has nested prereqs that will not match",
1710+
expected: false,
1711+
flags: flags,
1712+
preReqFlagPreReqs: []Prerequisite{
1713+
{Feature: "flag3",
1714+
Variations: []string{"false"},
1715+
},
1716+
},
1717+
target: nil,
1718+
},
1719+
{
1720+
name: "Given I have a preReqFlagPreReqs of a mv flag that has nested prereqs that will not match",
1721+
expected: false,
1722+
flags: flags,
1723+
preReqFlagPreReqs: []Prerequisite{
1724+
{Feature: "mv1",
1725+
Variations: []string{"blue"},
1726+
},
1727+
},
1728+
target: nil,
1729+
},
1730+
{
1731+
name: "Given I have a preReqFlagPreReqs of a mv flag that has nested prereqs that will match",
1732+
expected: true,
1733+
flags: flags,
1734+
preReqFlagPreReqs: []Prerequisite{
1735+
{Feature: "mv1",
1736+
Variations: []string{"red"},
1737+
},
1738+
},
1739+
target: nil,
1740+
},
1741+
}
1742+
1743+
for _, tt := range tests {
1744+
t.Run(tt.name, func(t *testing.T) {
1745+
assert.Equal(t, tt.expected, checkPreReqsForPreReqs(tt.preReqFlagPreReqs, tt.flags, tt.target))
1746+
})
1747+
}
1748+
}

examples/getting_started.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,24 +11,24 @@ import (
1111

1212
var (
1313
flagName string = getEnvOrDefault("FF_FLAG_NAME", "harnessappdemodarkmode")
14-
apiKey string = getEnvOrDefault("FF_API_KEY", "changeme")
14+
sdkKey string = getEnvOrDefault("FF_API_KEY", "changeme")
1515
)
1616

1717
func main() {
1818
log.Println("Harness SDK Getting Started")
1919

2020
// Create a feature flag client
21-
client, err := harness.NewCfClient(apiKey)
21+
client, err := harness.NewCfClient(sdkKey)
2222
if err != nil {
2323
log.Fatalf("could not connect to CF servers %s\n", err)
2424
}
2525
defer func() { client.Close() }()
2626

2727
// Create a target (different targets can get different results based on rules)
2828
target := evaluation.Target{
29-
Identifier: "golangsdk",
30-
Name: "GolangSDK",
31-
Attributes: &map[string]interface{}{"location": "emea"},
29+
Identifier: "HT_1",
30+
Name: "Harness_Target_1",
31+
Attributes: &map[string]interface{}{"email": "[email protected]"},
3232
}
3333

3434
// Loop forever reporting the state of the flag

0 commit comments

Comments
 (0)