Skip to content

Commit f185dd7

Browse files
Merge pull request #39 from DevLabFoundry/fix/data-race
fix: data race in token parsing
2 parents 06eea14 + 10b1b3c commit f185dd7

File tree

5 files changed

+38
-61
lines changed

5 files changed

+38
-61
lines changed

internal/store/store.go

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package store
22

33
import (
44
"errors"
5-
"fmt"
65

76
"github.com/DevLabFoundry/configmanager/v2/internal/config"
87
)
@@ -18,22 +17,9 @@ var (
1817

1918
// Strategy iface that all store implementations
2019
// must conform to, in order to be be used by the retrieval implementation
20+
//
21+
// Defined on the package for easier re-use across the program
2122
type Strategy interface {
2223
Token() (s string, e error)
2324
SetToken(s *config.ParsedTokenConfig)
2425
}
25-
26-
type DefaultStrategy struct {
27-
}
28-
29-
func NewDefatultStrategy() *DefaultStrategy {
30-
return &DefaultStrategy{}
31-
}
32-
33-
// SetToken on default strategy
34-
func (implmt *DefaultStrategy) SetToken(token *config.ParsedTokenConfig) {}
35-
36-
// Token
37-
func (implmt *DefaultStrategy) Token() (string, error) {
38-
return "", fmt.Errorf("default strategy does not implement token retrieval")
39-
}

internal/store/store_test.go

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1 @@
11
package store_test
2-
3-
import (
4-
"testing"
5-
6-
"github.com/DevLabFoundry/configmanager/v2/internal/store"
7-
)
8-
9-
func Test_StoreDefault(t *testing.T) {
10-
11-
t.Run("Default Shoudl not errror", func(t *testing.T) {
12-
rs := store.NewDefatultStrategy()
13-
if rs == nil {
14-
t.Fatal("unable to init default strategy")
15-
}
16-
})
17-
t.Run("Token method should error", func(t *testing.T) {
18-
rs := store.NewDefatultStrategy()
19-
if _, err := rs.Token(); err == nil {
20-
t.Fatal("Token should return not implemented error")
21-
}
22-
})
23-
24-
}

internal/strategy/strategy.go

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
1+
// Package strategy is a strategy pattern wrapper around the store implementations
2+
//
3+
// NOTE: this may be refactored out into the store package directly
14
package strategy
25

36
import (
47
"context"
58
"errors"
69
"fmt"
10+
"sync"
711

812
"github.com/DevLabFoundry/configmanager/v2/internal/config"
913
"github.com/DevLabFoundry/configmanager/v2/internal/log"
@@ -44,32 +48,43 @@ func defaultStrategyFuncMap(logger log.ILogger) map[config.ImplementationPrefix]
4448
}
4549
}
4650

51+
type strategyFnMap struct {
52+
mu sync.Mutex
53+
funcMap StrategyFuncMap
54+
}
4755
type RetrieveStrategy struct {
4856
implementation store.Strategy
4957
config config.GenVarsConfig
50-
strategyFuncMap StrategyFuncMap
51-
token string
58+
strategyFuncMap strategyFnMap
5259
}
60+
type Opts func(*RetrieveStrategy)
5361

5462
// New
55-
func New(s store.Strategy, config config.GenVarsConfig, logger log.ILogger) *RetrieveStrategy {
63+
func New(config config.GenVarsConfig, logger log.ILogger, opts ...Opts) *RetrieveStrategy {
5664
rs := &RetrieveStrategy{
57-
implementation: s,
5865
config: config,
59-
strategyFuncMap: defaultStrategyFuncMap(logger),
66+
strategyFuncMap: strategyFnMap{mu: sync.Mutex{}, funcMap: defaultStrategyFuncMap(logger)},
67+
}
68+
// overwrite or add any options/defaults set above
69+
for _, o := range opts {
70+
o(rs)
6071
}
72+
6173
return rs
6274
}
6375

6476
// WithStrategyFuncMap Adds custom implementations for prefix
6577
//
6678
// Mainly used for testing
6779
// NOTE: this may lead to eventual optional configurations by users
68-
func (rs *RetrieveStrategy) WithStrategyFuncMap(funcMap StrategyFuncMap) *RetrieveStrategy {
69-
for prefix, implementation := range funcMap {
70-
rs.strategyFuncMap[config.ImplementationPrefix(prefix)] = implementation
80+
func WithStrategyFuncMap(funcMap StrategyFuncMap) Opts {
81+
return func(rs *RetrieveStrategy) {
82+
for prefix, implementation := range funcMap {
83+
rs.strategyFuncMap.mu.Lock()
84+
defer rs.strategyFuncMap.mu.Unlock()
85+
rs.strategyFuncMap.funcMap[config.ImplementationPrefix(prefix)] = implementation
86+
}
7187
}
72-
return rs
7388
}
7489

7590
func (rs *RetrieveStrategy) setImplementation(strategy store.Strategy) {
@@ -120,7 +135,7 @@ func (rs *RetrieveStrategy) SelectImplementation(ctx context.Context, token *con
120135
return nil, fmt.Errorf("unable to get prefix, %w", ErrTokenInvalid)
121136
}
122137

123-
if store, found := rs.strategyFuncMap[token.Prefix()]; found {
138+
if store, found := rs.strategyFuncMap.funcMap[token.Prefix()]; found {
124139
return store(ctx, token)
125140
}
126141

internal/strategy/strategy_test.go

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ func Test_Strategy_Retrieve_succeeds(t *testing.T) {
6868
}
6969
for name, tt := range ttests {
7070
t.Run(name, func(t *testing.T) {
71-
rs := strategy.New(store.NewDefatultStrategy(), *tt.config, log.New(io.Discard))
71+
rs := strategy.New(*tt.config, log.New(io.Discard))
7272
token, _ := config.NewParsedTokenConfig(tt.token, *tt.config)
7373
got := rs.RetrieveByToken(context.TODO(), tt.impl(t), token)
7474
if got.Err != nil {
@@ -103,8 +103,7 @@ func Test_CustomStrategyFuncMap_add_own(t *testing.T) {
103103
return m, nil
104104
}
105105

106-
s := strategy.New(store.NewDefatultStrategy(), *genVarsConf, log.New(io.Discard))
107-
s.WithStrategyFuncMap(strategy.StrategyFuncMap{config.AzTableStorePrefix: custFunc})
106+
s := strategy.New(*genVarsConf, log.New(io.Discard), strategy.WithStrategyFuncMap(strategy.StrategyFuncMap{config.AzTableStorePrefix: custFunc}))
108107

109108
store, _ := s.SelectImplementation(context.TODO(), token)
110109
_ = s.RetrieveByToken(context.TODO(), store, token)
@@ -273,7 +272,7 @@ func Test_SelectImpl_With(t *testing.T) {
273272
tearDown := tt.setUpTearDown()
274273
defer tearDown()
275274
want := tt.expect()
276-
rs := strategy.New(store.NewDefatultStrategy(), *tt.config, log.New(io.Discard))
275+
rs := strategy.New(*tt.config, log.New(io.Discard))
277276
token, _ := config.NewParsedTokenConfig(tt.token, *tt.config)
278277
got, err := rs.SelectImplementation(context.TODO(), token)
279278

pkg/generator/generator.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ type retrieveIface interface {
2929
// relevant strategy network calls to the config store implementations
3030
type GenVars struct {
3131
Logger log.ILogger
32-
strategy retrieveIface
32+
strategy strategy.StrategyFuncMap
3333
ctx context.Context
3434
config config.GenVarsConfig
3535
// rawMap is the internal object that holds the values
@@ -61,22 +61,21 @@ func newGenVars(ctx context.Context, opts ...Opts) *GenVars {
6161
// return using default config
6262
config: *conf,
6363
}
64+
g.strategy = nil
6465

66+
// now apply additional opts
6567
for _, o := range opts {
6668
o(g)
6769
}
6870

69-
// using a default Strategy
70-
g.strategy = strategy.New(store.NewDefatultStrategy(), *conf, g.Logger)
71-
// now apply
7271
return g
7372
}
7473

7574
// WithStrategyMap
7675
//
77-
// Adds addtional funcs for storageRetrieval
76+
// Adds addtional funcs for storageRetrieval used for testing only
7877
func (c *GenVars) WithStrategyMap(sm strategy.StrategyFuncMap) *GenVars {
79-
c.strategy.WithStrategyFuncMap(sm)
78+
c.strategy = sm
8079
return c
8180
}
8281

@@ -195,12 +194,13 @@ func (c *GenVars) generate(rawMap *rawTokenMap) error {
195194
token := parsedToken // safe closure capture
196195
// take value from config allocation on a per iteration basis
197196
go func() {
198-
storeStrategy, err := c.strategy.SelectImplementation(c.ctx, token)
197+
s := strategy.New(c.config, c.Logger, strategy.WithStrategyFuncMap(c.strategy))
198+
storeStrategy, err := s.SelectImplementation(c.ctx, token)
199199
if err != nil {
200200
outCh <- &strategy.TokenResponse{Err: err}
201201
return
202202
}
203-
outCh <- c.strategy.RetrieveByToken(c.ctx, storeStrategy, token)
203+
outCh <- s.RetrieveByToken(c.ctx, storeStrategy, token)
204204
}()
205205
}
206206

0 commit comments

Comments
 (0)