You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficcontrol.apache.org by de...@apache.org on 2018/02/07 15:04:10 UTC
[incubator-trafficcontrol] 07/13: deal with race condition
This is an automated email from the ASF dual-hosted git repository.
dewrich pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-trafficcontrol.git
commit f1c4952c2df2266ba4ad331af22470c650b1a5df
Author: Dan Kirkwood <da...@gmail.com>
AuthorDate: Wed Dec 13 12:55:50 2017 -0700
deal with race condition
---
traffic_ops/testing/compare/compare.go | 186 +++++++++++++++++++--------------
1 file changed, 109 insertions(+), 77 deletions(-)
diff --git a/traffic_ops/testing/compare/compare.go b/traffic_ops/testing/compare/compare.go
index f27b393..ac99250 100644
--- a/traffic_ops/testing/compare/compare.go
+++ b/traffic_ops/testing/compare/compare.go
@@ -15,8 +15,10 @@ package main
//
import (
+ "bufio"
"bytes"
"encoding/json"
+ "flag"
"fmt"
"io/ioutil"
"log"
@@ -32,18 +34,6 @@ import (
"golang.org/x/net/publicsuffix"
)
-var testRoutes = []string{
- `api/1.2/asns?orderby=id`,
- `api/1.2/cdns?orderby=id`,
- `api/1.2/divisions?orderby=id`,
- `api/1.2/parameters?orderby=id`,
- `api/1.2/phys_locations?orderby=id`,
- `api/1.2/regions?orderby=id`,
- `api/1.2/servers?orderby=id`,
- `api/1.2/statuses?orderby=id`,
- `api/1.2/profiles?orderby=id`,
-}
-
// Environment variables used:
// TO_URL -- URL for reference Traffic Ops
// TEST_URL -- URL for test Traffic Ops
@@ -65,10 +55,6 @@ type Connect struct {
ResultsPath string
}
-// refTO, newTO are connections to the two Traffic Ops instances
-var refTO = &Connect{ResultsPath: `./results/ref`}
-var newTO = &Connect{ResultsPath: `./results/new`}
-
func (to *Connect) login(creds Creds) error {
body, err := json.Marshal(creds)
if err != nil {
@@ -83,7 +69,7 @@ func (to *Connect) login(creds Creds) error {
}
req.Header.Set("Content-Type", "application/json")
- // Create cookiejar for created cookie to be placed into
+ // Create cookiejar so created cookie will be reused
jar, err := cookiejar.New(&cookiejar.Options{PublicSuffixList: publicsuffix.List})
if err != nil {
return err
@@ -105,52 +91,57 @@ func (to *Connect) login(creds Creds) error {
return nil
}
-func doGetRoute(to *Connect, route string, res *[]byte) {
- var err error
- *res, err = to.get(route)
- if err != nil {
- *res = []byte(fmt.Sprintf("Error from %s : %s", to.URL+route, err))
+func testRoute(tos []*Connect, route string) {
+ // keeps result along with instance -- no guarantee on order collected
+ type result struct {
+ TO *Connect
+ Res string
}
-}
+ var res []result
+ ch := make(chan result, len(tos))
-func testRoute(route string) {
var wg sync.WaitGroup
- wg.Add(2)
-
- var res1, res2 []byte
- go func() {
- doGetRoute(refTO, route, &res1)
- wg.Done()
- }()
+ var m sync.Mutex
- go func() {
- doGetRoute(newTO, route, &res2)
- wg.Done()
- }()
+ for _, to := range tos {
+ wg.Add(1)
+ go func(to *Connect) {
+ s, err := to.get(route)
+ if err != nil {
+ s = err.Error()
+ }
+ ch <- result{to, s}
+ wg.Done()
+ }(to)
+ wg.Add(1)
+ go func() {
+ m.Lock()
+ defer m.Unlock()
+ res = append(res, <-ch)
+ wg.Done()
+ }()
+ }
wg.Wait()
+ close(ch)
- if bytes.Equal(res1, res2) {
- log.Printf("Identical results (%d bytes) from %s", len(res1), route)
+ if res[0].Res == res[1].Res {
+ log.Printf("Identical results (%d bytes) from %s", len(res[0].Res), route)
} else {
- refPath, err := refTO.writeResults(route, res1)
- if err != nil {
- log.Fatal("Error writing results for ", route)
- }
-
- newPath, err := newTO.writeResults(route, res2)
- if err != nil {
- log.Fatal("Error writing results for ", route)
- }
log.Print("Diffs from ", route, " written to")
- log.Print(" ", refPath)
- log.Print(" ", newPath)
+ for _, r := range res {
+ p, err := r.TO.writeResults(route, r.Res)
+ if err != nil {
+ log.Fatal("Error writing results for ", route)
+ }
+ log.Print(" ", p)
+ }
}
}
-func (to *Connect) writeResults(route string, res []byte) (string, error) {
+func (to *Connect) writeResults(route string, res string) (string, error) {
var dst bytes.Buffer
- json.Indent(&dst, res, "", " ")
+ json.Indent(&dst, []byte(res), "", " ")
m := func(r rune) rune {
if unicode.IsPunct(r) && r != '.' || unicode.IsSymbol(r) {
@@ -169,32 +160,34 @@ func (to *Connect) writeResults(route string, res []byte) (string, error) {
return p, err
}
-func (to *Connect) get(route string) ([]byte, error) {
+func (to *Connect) get(route string) (string, error) {
url := to.URL + `/` + route
req, err := http.NewRequest("GET", url, nil)
if err != nil {
- return nil, err
+ return "", err
}
req.Header.Set("Content-Type", "application/json")
resp, err := to.Client.Do(req)
if err != nil {
- return nil, err
+ return "", err
}
defer resp.Body.Close()
data, err := ioutil.ReadAll(resp.Body)
- return data, err
+ return string(data), err
}
-func getCDNNames(c *Connect) ([]string, error) {
- var res []byte
- doGetRoute(c, `api/1.2/cdns`, &res)
- fmt.Println(string(res))
+func (to *Connect) getCDNNames() ([]string, error) {
+ res, err := to.get(`api/1.2/cdns`)
+ if err != nil {
+ return nil, err
+ }
+ fmt.Println(res)
var cdnResp tc.CDNsResponse
- err := json.Unmarshal(res, &cdnResp)
+ err = json.Unmarshal([]byte(res), &cdnResp)
if err != nil {
return nil, err
}
@@ -206,11 +199,26 @@ func getCDNNames(c *Connect) ([]string, error) {
}
func main() {
+ var routesFile string
+ var route string
+ var resultsPath string
+ var doSnapshot bool
+
+ flag.StringVar(&routesFile, "file", "./testroutes.txt", "File listing routes to test (ignored if -route is used)")
+ flag.StringVar(&route, "route", "", "Single route to test")
+ flag.StringVar(&resultsPath, "results", "results", "Directory to write results")
+ flag.BoolVar(&doSnapshot, "snapshot", false, "Do snapshot comparison for each CDN")
+ flag.Parse()
+
err := envconfig.Process("TO", &creds)
if err != nil {
log.Fatal(err.Error())
}
+ // refTO, newTO are connections to the two Traffic Ops instances
+ var refTO = &Connect{ResultsPath: resultsPath + `/ref`}
+ var newTO = &Connect{ResultsPath: resultsPath + `/new`}
+
err = envconfig.Process("TO", refTO)
if err != nil {
log.Fatal(err.Error())
@@ -221,10 +229,10 @@ func main() {
log.Fatal(err.Error())
}
+ tos := []*Connect{refTO, newTO}
+
// Login to the 2 Traffic Ops instances concurrently
var wg sync.WaitGroup
-
- tos := []*Connect{refTO, newTO}
wg.Add(len(tos))
for _, t := range tos {
go func(to *Connect) {
@@ -236,31 +244,55 @@ func main() {
wg.Done()
}(t)
}
-
wg.Wait()
+ var testRoutes []string
+
+ if route != "" {
+ // -route (specify single route) takes precedence
+ testRoutes = append(testRoutes, route)
+ } else if routesFile != "" {
+ // -file (specify route) takes precedence
+ file, err := os.Open(routesFile)
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer file.Close()
+
+ scanner := bufio.NewScanner(file)
+ for scanner.Scan() {
+ testRoutes = append(testRoutes, scanner.Text())
+ }
+
+ if err := scanner.Err(); err != nil {
+ log.Fatal(err)
+ }
+ }
+
wg.Add(len(testRoutes))
for _, route := range testRoutes {
go func(r string) {
- testRoute(r)
+ testRoute(tos, r)
wg.Done()
}(route)
}
wg.Wait()
- cdnNames, err := getCDNNames(refTO)
- if err != nil {
- panic(err)
- }
- log.Printf("CDNNames are %+v", cdnNames)
- wg.Add(len(cdnNames))
- for _, cdnName := range cdnNames {
- log.Print("CDN ", cdnName)
- go func(c string) {
- testRoute(`api/1.2/cdns/` + c + `/snapshot/new`)
- wg.Done()
- }(cdnName)
+ if doSnapshot {
+ cdnNames, err := refTO.getCDNNames()
+ if err != nil {
+ panic(err)
+ }
+ log.Printf("CDNNames are %+v", cdnNames)
+
+ wg.Add(len(cdnNames))
+ for _, cdnName := range cdnNames {
+ log.Print("CDN ", cdnName)
+ go func(c string) {
+ testRoute(tos, `api/1.2/cdns/`+c+`/snapshot/new`)
+ wg.Done()
+ }(cdnName)
+ }
+ wg.Wait()
}
- wg.Wait()
-
}
--
To stop receiving notification emails like this one, please contact
dewrich@apache.org.