add sync tests

This commit is contained in:
bakito 2021-04-11 17:30:47 +02:00
parent 4921af09a5
commit da3b037009
No known key found for this signature in database
GPG key ID: FAF93C1C384DD6B4
3 changed files with 373 additions and 73 deletions

View file

@ -262,6 +262,35 @@ bar`)
Ω(err).ShouldNot(HaveOccurred()) Ω(err).ShouldNot(HaveOccurred())
}) })
}) })
Context("helper functions", func() {
var (
cl client.Client
)
BeforeEach(func() {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusUnauthorized)
}))
var err error
cl, err = client.New(types.AdGuardInstance{URL: ts.URL})
Ω(err).ShouldNot(HaveOccurred())
})
Context("doGet", func() {
It("should return an error on status code != 200", func() {
_, err := cl.Status()
Ω(err).Should(HaveOccurred())
Ω(err.Error()).Should(Equal("401 Unauthorized"))
})
})
Context("doPost", func() {
It("should return an error on status code != 200", func() {
err := cl.SetStatsConfig(123)
Ω(err).Should(HaveOccurred())
Ω(err.Error()).Should(Equal("401 Unauthorized"))
})
})
})
}) })
func ClientGet(file string, path string) (*httptest.Server, client.Client) { func ClientGet(file string, path string) (*httptest.Server, client.Client) {

View file

@ -28,6 +28,9 @@ func Sync(cfg *types.Config) error {
w := &worker{ w := &worker{
cfg: cfg, cfg: cfg,
createClient: func(ai types.AdGuardInstance) (client.Client, error) {
return client.New(ai)
},
} }
if cfg.Cron != "" { if cfg.Cron != "" {
w.cron = cron.New() w.cron = cron.New()
@ -55,9 +58,10 @@ func Sync(cfg *types.Config) error {
} }
type worker struct { type worker struct {
cfg *types.Config cfg *types.Config
running bool running bool
cron *cron.Cron cron *cron.Cron
createClient func(instance types.AdGuardInstance) (client.Client, error)
} }
func (w *worker) sync() { func (w *worker) sync() {
@ -68,7 +72,7 @@ func (w *worker) sync() {
w.running = true w.running = true
defer func() { w.running = false }() defer func() { w.running = false }()
oc, err := client.New(w.cfg.Origin) oc, err := w.createClient(w.cfg.Origin)
if err != nil { if err != nil {
l.With("error", err, "url", w.cfg.Origin.URL).Error("Error creating origin client") l.With("error", err, "url", w.cfg.Origin.URL).Error("Error creating origin client")
return return
@ -77,7 +81,6 @@ func (w *worker) sync() {
sl := l.With("from", oc.Host()) sl := l.With("from", oc.Host())
o := &origin{} o := &origin{}
o.status, err = oc.Status() o.status, err = oc.Status()
if err != nil { if err != nil {
sl.With("error", err).Error("Error getting origin status") sl.With("error", err).Error("Error getting origin status")
@ -141,7 +144,7 @@ func (w *worker) sync() {
func (w *worker) syncTo(l *zap.SugaredLogger, o *origin, replica types.AdGuardInstance) { func (w *worker) syncTo(l *zap.SugaredLogger, o *origin, replica types.AdGuardInstance) {
rc, err := client.New(replica) rc, err := w.createClient(replica)
if err != nil { if err != nil {
l.With("error", err, "url", replica.URL).Error("Error creating replica client") l.With("error", err, "url", replica.URL).Error("Error creating replica client")
return return
@ -166,7 +169,7 @@ func (w *worker) syncTo(l *zap.SugaredLogger, o *origin, replica types.AdGuardIn
return return
} }
err = w.syncConfigs(o, rs, rc) err = w.syncConfigs(o, rc)
if err != nil { if err != nil {
l.With("error", err).Error("Error syncing configs") l.With("error", err).Error("Error syncing configs")
return return
@ -217,40 +220,10 @@ func (w *worker) syncFilters(of *types.FilteringStatus, replica client.Client) e
return err return err
} }
fa, fu, fd := rf.Filters.Merge(of.Filters) if err = w.syncFilterType(of, rf.Filters, false, replica); err != nil {
if err = replica.AddFilters(false, fa...); err != nil {
return err return err
} }
if err = replica.UpdateFilters(false, fu...); err != nil { if err = w.syncFilterType(of, rf.WhitelistFilters, true, replica); err != nil {
return err
}
if len(fa) > 0 || len(fu) > 0 {
if err = replica.RefreshFilters(false); err != nil {
return err
}
}
if err = replica.DeleteFilters(false, fd...); err != nil {
return err
}
fa, fu, fd = rf.WhitelistFilters.Merge(of.WhitelistFilters)
if err = replica.AddFilters(true, fa...); err != nil {
return err
}
if err = replica.UpdateFilters(true, fu...); err != nil {
return err
}
if len(fa) > 0 || len(fu) > 0 {
if err = replica.RefreshFilters(true); err != nil {
return err
}
}
if err = replica.DeleteFilters(true, fd...); err != nil {
return err return err
} }
@ -266,6 +239,28 @@ func (w *worker) syncFilters(of *types.FilteringStatus, replica client.Client) e
return nil return nil
} }
func (w *worker) syncFilterType(of *types.FilteringStatus, rFilters types.Filters, whitelist bool, replica client.Client) error {
fa, fu, fd := rFilters.Merge(of.Filters)
if err := replica.AddFilters(whitelist, fa...); err != nil {
return err
}
if err := replica.UpdateFilters(whitelist, fu...); err != nil {
return err
}
if len(fa) > 0 || len(fu) > 0 {
if err := replica.RefreshFilters(whitelist); err != nil {
return err
}
}
if err := replica.DeleteFilters(whitelist, fd...); err != nil {
return err
}
return nil
}
func (w *worker) syncRewrites(or *types.RewriteEntries, replica client.Client) error { func (w *worker) syncRewrites(or *types.RewriteEntries, replica client.Client) error {
replicaRewrites, err := replica.RewriteList() replicaRewrites, err := replica.RewriteList()
@ -334,7 +329,7 @@ func (w *worker) syncGeneralSettings(o *origin, rs *types.Status, replica client
return nil return nil
} }
func (w *worker) syncConfigs(o *origin, rs *types.Status, replica client.Client) error { func (w *worker) syncConfigs(o *origin, replica client.Client) error {
qlc, err := replica.QueryLogConfig() qlc, err := replica.QueryLogConfig()
if err != nil { if err != nil {
return err return err

View file

@ -2,6 +2,7 @@ package sync
import ( import (
"errors" "errors"
"github.com/bakito/adguardhome-sync/pkg/client"
. "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
@ -15,15 +16,19 @@ import (
var _ = Describe("Sync", func() { var _ = Describe("Sync", func() {
var ( var (
mockCtrl *gm.Controller mockCtrl *gm.Controller
client *mc.MockClient cl *mc.MockClient
w *worker w *worker
te error te error
) )
BeforeEach(func() { BeforeEach(func() {
mockCtrl = gm.NewController(GinkgoT()) mockCtrl = gm.NewController(GinkgoT())
client = mc.NewMockClient(mockCtrl) cl = mc.NewMockClient(mockCtrl)
w = &worker{} w = &worker{
createClient: func(instance types.AdGuardInstance) (client.Client, error) {
return cl, nil
},
}
te = errors.New(uuid.NewString()) te = errors.New(uuid.NewString())
}) })
AfterEach(func() { AfterEach(func() {
@ -46,64 +51,335 @@ var _ = Describe("Sync", func() {
reR = []types.RewriteEntry{{Domain: domain, Answer: answer}} reR = []types.RewriteEntry{{Domain: domain, Answer: answer}}
}) })
It("should have no changes (empty slices)", func() { It("should have no changes (empty slices)", func() {
client.EXPECT().RewriteList().Return(&reR, nil) cl.EXPECT().RewriteList().Return(&reR, nil)
client.EXPECT().AddRewriteEntries() cl.EXPECT().AddRewriteEntries()
client.EXPECT().DeleteRewriteEntries() cl.EXPECT().DeleteRewriteEntries()
err := w.syncRewrites(&reO, client) err := w.syncRewrites(&reO, cl)
Ω(err).ShouldNot(HaveOccurred()) Ω(err).ShouldNot(HaveOccurred())
}) })
It("should add one rewrite entry", func() { It("should add one rewrite entry", func() {
reR = []types.RewriteEntry{} reR = []types.RewriteEntry{}
client.EXPECT().RewriteList().Return(&reR, nil) cl.EXPECT().RewriteList().Return(&reR, nil)
client.EXPECT().AddRewriteEntries(reO[0]) cl.EXPECT().AddRewriteEntries(reO[0])
client.EXPECT().DeleteRewriteEntries() cl.EXPECT().DeleteRewriteEntries()
err := w.syncRewrites(&reO, client) err := w.syncRewrites(&reO, cl)
Ω(err).ShouldNot(HaveOccurred()) Ω(err).ShouldNot(HaveOccurred())
}) })
It("should remove one rewrite entry", func() { It("should remove one rewrite entry", func() {
reO = []types.RewriteEntry{} reO = []types.RewriteEntry{}
client.EXPECT().RewriteList().Return(&reR, nil) cl.EXPECT().RewriteList().Return(&reR, nil)
client.EXPECT().AddRewriteEntries() cl.EXPECT().AddRewriteEntries()
client.EXPECT().DeleteRewriteEntries(reR[0]) cl.EXPECT().DeleteRewriteEntries(reR[0])
err := w.syncRewrites(&reO, client) err := w.syncRewrites(&reO, cl)
Ω(err).ShouldNot(HaveOccurred())
})
It("should remove one rewrite entry", func() {
reO = []types.RewriteEntry{}
cl.EXPECT().RewriteList().Return(&reR, nil)
cl.EXPECT().AddRewriteEntries()
cl.EXPECT().DeleteRewriteEntries(reR[0])
err := w.syncRewrites(&reO, cl)
Ω(err).ShouldNot(HaveOccurred()) Ω(err).ShouldNot(HaveOccurred())
}) })
It("should return error when error on RewriteList()", func() { It("should return error when error on RewriteList()", func() {
client.EXPECT().RewriteList().Return(nil, te) cl.EXPECT().RewriteList().Return(nil, te)
err := w.syncRewrites(&reO, client) err := w.syncRewrites(&reO, cl)
Ω(err).Should(HaveOccurred()) Ω(err).Should(HaveOccurred())
}) })
It("should return error when error on AddRewriteEntries()", func() { It("should return error when error on AddRewriteEntries()", func() {
client.EXPECT().RewriteList().Return(&reR, nil) cl.EXPECT().RewriteList().Return(&reR, nil)
client.EXPECT().AddRewriteEntries().Return(te) cl.EXPECT().AddRewriteEntries().Return(te)
err := w.syncRewrites(&reO, client) err := w.syncRewrites(&reO, cl)
Ω(err).Should(HaveOccurred()) Ω(err).Should(HaveOccurred())
}) })
It("should return error when error on DeleteRewriteEntries()", func() { It("should return error when error on DeleteRewriteEntries()", func() {
client.EXPECT().RewriteList().Return(&reR, nil) cl.EXPECT().RewriteList().Return(&reR, nil)
client.EXPECT().AddRewriteEntries() cl.EXPECT().AddRewriteEntries()
client.EXPECT().DeleteRewriteEntries().Return(te) cl.EXPECT().DeleteRewriteEntries().Return(te)
err := w.syncRewrites(&reO, client) err := w.syncRewrites(&reO, cl)
Ω(err).Should(HaveOccurred()) Ω(err).Should(HaveOccurred())
}) })
}) })
Context("syncClients", func() { Context("syncClients", func() {
var ( var (
clO *types.Clients clO *types.Clients
clR *types.Clients clR *types.Clients
name string
) )
BeforeEach(func() { BeforeEach(func() {
clO = &types.Clients{} name = uuid.NewString()
clR = &types.Clients{} clO = &types.Clients{Clients: []types.Client{{Name: name}}}
clR = &types.Clients{Clients: []types.Client{{Name: name}}}
}) })
It("should have no changes (empty slices)", func() { It("should have no changes (empty slices)", func() {
client.EXPECT().Clients().Return(clR, nil) cl.EXPECT().Clients().Return(clR, nil)
client.EXPECT().AddClients() cl.EXPECT().AddClients()
client.EXPECT().UpdateClients() cl.EXPECT().UpdateClients()
client.EXPECT().DeleteClients() cl.EXPECT().DeleteClients()
err := w.syncClients(clO, client) err := w.syncClients(clO, cl)
Ω(err).ShouldNot(HaveOccurred()) Ω(err).ShouldNot(HaveOccurred())
}) })
It("should add one client", func() {
clR.Clients = []types.Client{}
cl.EXPECT().Clients().Return(clR, nil)
cl.EXPECT().AddClients(clO.Clients[0])
cl.EXPECT().UpdateClients()
cl.EXPECT().DeleteClients()
err := w.syncClients(clO, cl)
Ω(err).ShouldNot(HaveOccurred())
})
It("should update one client", func() {
clR.Clients[0].Disallowed = true
cl.EXPECT().Clients().Return(clR, nil)
cl.EXPECT().AddClients()
cl.EXPECT().UpdateClients(clO.Clients[0])
cl.EXPECT().DeleteClients()
err := w.syncClients(clO, cl)
Ω(err).ShouldNot(HaveOccurred())
})
It("should delete one client", func() {
clO.Clients = []types.Client{}
cl.EXPECT().Clients().Return(clR, nil)
cl.EXPECT().AddClients()
cl.EXPECT().UpdateClients()
cl.EXPECT().DeleteClients(clR.Clients[0])
err := w.syncClients(clO, cl)
Ω(err).ShouldNot(HaveOccurred())
})
It("should return error when error on Clients()", func() {
cl.EXPECT().Clients().Return(nil, te)
err := w.syncClients(clO, cl)
Ω(err).Should(HaveOccurred())
})
It("should return error when error on AddClients()", func() {
cl.EXPECT().Clients().Return(clR, nil)
cl.EXPECT().AddClients().Return(te)
err := w.syncClients(clO, cl)
Ω(err).Should(HaveOccurred())
})
It("should return error when error on UpdateClients()", func() {
cl.EXPECT().Clients().Return(clR, nil)
cl.EXPECT().AddClients()
cl.EXPECT().UpdateClients().Return(te)
err := w.syncClients(clO, cl)
Ω(err).Should(HaveOccurred())
})
It("should return error when error on DeleteClients()", func() {
cl.EXPECT().Clients().Return(clR, nil)
cl.EXPECT().AddClients()
cl.EXPECT().UpdateClients()
cl.EXPECT().DeleteClients().Return(te)
err := w.syncClients(clO, cl)
Ω(err).Should(HaveOccurred())
})
})
Context("syncGeneralSettings", func() {
var (
o *origin
rs *types.Status
)
BeforeEach(func() {
o = &origin{
status: &types.Status{},
}
rs = &types.Status{}
})
It("should have no changes", func() {
cl.EXPECT().Parental()
cl.EXPECT().SafeSearch()
cl.EXPECT().SafeBrowsing()
err := w.syncGeneralSettings(o, rs, cl)
Ω(err).ShouldNot(HaveOccurred())
})
It("should have protection enabled changes", func() {
o.status.ProtectionEnabled = true
cl.EXPECT().ToggleProtection(true)
cl.EXPECT().Parental()
cl.EXPECT().SafeSearch()
cl.EXPECT().SafeBrowsing()
err := w.syncGeneralSettings(o, rs, cl)
Ω(err).ShouldNot(HaveOccurred())
})
It("should have parental enabled changes", func() {
o.parental = true
cl.EXPECT().Parental()
cl.EXPECT().ToggleParental(true)
cl.EXPECT().SafeSearch()
cl.EXPECT().SafeBrowsing()
err := w.syncGeneralSettings(o, rs, cl)
Ω(err).ShouldNot(HaveOccurred())
})
It("should have safeSearch enabled changes", func() {
o.safeSearch = true
cl.EXPECT().Parental()
cl.EXPECT().SafeSearch()
cl.EXPECT().ToggleSafeSearch(true)
cl.EXPECT().SafeBrowsing()
err := w.syncGeneralSettings(o, rs, cl)
Ω(err).ShouldNot(HaveOccurred())
})
It("should have safeBrowsing enabled changes", func() {
o.safeBrowsing = true
cl.EXPECT().Parental()
cl.EXPECT().SafeSearch()
cl.EXPECT().SafeBrowsing()
cl.EXPECT().ToggleSafeBrowsing(true)
err := w.syncGeneralSettings(o, rs, cl)
Ω(err).ShouldNot(HaveOccurred())
})
})
Context("syncConfigs", func() {
var (
o *origin
qlc *types.QueryLogConfig
sc *types.IntervalConfig
)
BeforeEach(func() {
o = &origin{
queryLogConfig: &types.QueryLogConfig{},
statsConfig: &types.IntervalConfig{},
}
qlc = &types.QueryLogConfig{}
sc = &types.IntervalConfig{}
})
It("should have no changes", func() {
cl.EXPECT().QueryLogConfig().Return(qlc, nil)
cl.EXPECT().StatsConfig().Return(sc, nil)
err := w.syncConfigs(o, cl)
Ω(err).ShouldNot(HaveOccurred())
})
It("should have QueryLogConfig changes", func() {
o.queryLogConfig.Interval = 123
cl.EXPECT().QueryLogConfig().Return(qlc, nil)
cl.EXPECT().SetQueryLogConfig(false, 123, false)
cl.EXPECT().StatsConfig().Return(sc, nil)
err := w.syncConfigs(o, cl)
Ω(err).ShouldNot(HaveOccurred())
})
It("should have StatsConfig changes", func() {
o.statsConfig.Interval = 123
cl.EXPECT().QueryLogConfig().Return(qlc, nil)
cl.EXPECT().StatsConfig().Return(sc, nil)
cl.EXPECT().SetStatsConfig(123)
err := w.syncConfigs(o, cl)
Ω(err).ShouldNot(HaveOccurred())
})
})
Context("syncServices", func() {
var (
os types.Services
rs types.Services
)
BeforeEach(func() {
os = []string{"foo"}
rs = []string{"foo"}
})
It("should have no changes", func() {
cl.EXPECT().Services().Return(rs, nil)
err := w.syncServices(os, cl)
Ω(err).ShouldNot(HaveOccurred())
})
It("should have services changes", func() {
os = []string{"bar"}
cl.EXPECT().Services().Return(rs, nil)
cl.EXPECT().SetServices(os)
err := w.syncServices(os, cl)
Ω(err).ShouldNot(HaveOccurred())
})
})
Context("syncFilters", func() {
var (
of *types.FilteringStatus
rf *types.FilteringStatus
)
BeforeEach(func() {
of = &types.FilteringStatus{}
rf = &types.FilteringStatus{}
})
It("should have no changes", func() {
cl.EXPECT().Filtering().Return(rf, nil)
cl.EXPECT().AddFilters(false)
cl.EXPECT().UpdateFilters(false)
cl.EXPECT().DeleteFilters(false)
cl.EXPECT().AddFilters(true)
cl.EXPECT().UpdateFilters(true)
cl.EXPECT().DeleteFilters(true)
err := w.syncFilters(of, cl)
Ω(err).ShouldNot(HaveOccurred())
})
It("should have changes user roles", func() {
of.UserRules = []string{"foo"}
cl.EXPECT().Filtering().Return(rf, nil)
cl.EXPECT().AddFilters(false)
cl.EXPECT().UpdateFilters(false)
cl.EXPECT().DeleteFilters(false)
cl.EXPECT().AddFilters(true)
cl.EXPECT().UpdateFilters(true)
cl.EXPECT().DeleteFilters(true)
cl.EXPECT().SetCustomRules(of.UserRules)
err := w.syncFilters(of, cl)
Ω(err).ShouldNot(HaveOccurred())
})
It("should have changed filtering config", func() {
of.Enabled = true
of.Interval = 123
cl.EXPECT().Filtering().Return(rf, nil)
cl.EXPECT().AddFilters(false)
cl.EXPECT().UpdateFilters(false)
cl.EXPECT().DeleteFilters(false)
cl.EXPECT().AddFilters(true)
cl.EXPECT().UpdateFilters(true)
cl.EXPECT().DeleteFilters(true)
cl.EXPECT().ToggleFiltering(of.Enabled, of.Interval)
err := w.syncFilters(of, cl)
Ω(err).ShouldNot(HaveOccurred())
})
})
Context("sync", func() {
It("should have no changes", func() {
w.cfg = &types.Config{
Origin: types.AdGuardInstance{},
Replica: types.AdGuardInstance{URL: "foo"},
}
// origin
cl.EXPECT().Host()
cl.EXPECT().Status().Return(&types.Status{}, nil)
cl.EXPECT().Parental()
cl.EXPECT().SafeSearch()
cl.EXPECT().SafeBrowsing()
cl.EXPECT().RewriteList().Return(&types.RewriteEntries{}, nil)
cl.EXPECT().Services()
cl.EXPECT().Filtering().Return(&types.FilteringStatus{}, nil)
cl.EXPECT().Clients().Return(&types.Clients{}, nil)
cl.EXPECT().QueryLogConfig().Return(&types.QueryLogConfig{}, nil)
cl.EXPECT().StatsConfig().Return(&types.IntervalConfig{}, nil)
// replica
cl.EXPECT().Host()
cl.EXPECT().Status().Return(&types.Status{}, nil)
cl.EXPECT().Parental()
cl.EXPECT().SafeSearch()
cl.EXPECT().SafeBrowsing()
cl.EXPECT().QueryLogConfig().Return(&types.QueryLogConfig{}, nil)
cl.EXPECT().StatsConfig().Return(&types.IntervalConfig{}, nil)
cl.EXPECT().RewriteList().Return(&types.RewriteEntries{}, nil)
cl.EXPECT().AddRewriteEntries()
cl.EXPECT().DeleteRewriteEntries()
cl.EXPECT().Filtering().Return(&types.FilteringStatus{}, nil)
cl.EXPECT().AddFilters(false)
cl.EXPECT().UpdateFilters(false)
cl.EXPECT().DeleteFilters(false)
cl.EXPECT().AddFilters(true)
cl.EXPECT().UpdateFilters(true)
cl.EXPECT().DeleteFilters(true)
cl.EXPECT().Services()
cl.EXPECT().Clients().Return(&types.Clients{}, nil)
cl.EXPECT().AddClients()
cl.EXPECT().UpdateClients()
cl.EXPECT().DeleteClients()
w.sync()
})
}) })
}) })
}) })