blob: d0d80498cc19601f6c36dbe9ea48ee39ad43e5d6 [file] [log] [blame]
Kent Hagerman433a31a2020-05-20 19:04:48 -04001/*
2 * Copyright 2020-present Open Networking Foundation
3
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7
8 * http://www.apache.org/licenses/LICENSE-2.0
9
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package flow
18
19import (
20 "bufio"
Andrey Pozolotin34dd63f2021-05-31 21:26:40 +030021 "context"
Kent Hagerman433a31a2020-05-20 19:04:48 -040022 "fmt"
23 "os"
Andrey Pozolotin34dd63f2021-05-31 21:26:40 +030024 "path/filepath"
Kent Hagerman433a31a2020-05-20 19:04:48 -040025 "regexp"
26 "strconv"
Kent Hagerman433a31a2020-05-20 19:04:48 -040027 "testing"
28)
29
30// TestLoadersIdentical ensures that the group, flow, and meter loaders always have an identical implementation.
31func TestLoadersIdentical(t *testing.T) {
khenaidoo1a0d6222021-06-30 16:48:44 -040032 types := []string{"flow", "group"}
Kent Hagermanfa9d6d42020-05-25 11:49:40 -040033
Kent Hagerman433a31a2020-05-20 19:04:48 -040034 identical := [][]string{
khenaidoo1a0d6222021-06-30 16:48:44 -040035 {`ofp\.OfpFlowStats`, `ofp\.OfpGroupEntry`},
36 {`\.Id`, `\.Desc\.GroupId`},
37 {`uint64`, `uint32`},
38 {`Flow`, `Group`},
39 {`flow`, `group`},
Kent Hagerman433a31a2020-05-20 19:04:48 -040040 }
41
Kent Hagermanfa9d6d42020-05-25 11:49:40 -040042 regexes := make([][]*regexp.Regexp, len(identical[0]))
43 for i := range regexes {
44 regexes[i] = make([]*regexp.Regexp, len(identical))
45 }
Kent Hagerman433a31a2020-05-20 19:04:48 -040046 for i, group := range identical {
Kent Hagermanfa9d6d42020-05-25 11:49:40 -040047 for j, regexStr := range group {
48 // convert from column-wise to row-wise for convenience
49 regexes[j][i] = regexp.MustCompile(regexStr)
50 }
Kent Hagerman433a31a2020-05-20 19:04:48 -040051 }
52
Kent Hagermanfa9d6d42020-05-25 11:49:40 -040053 for i := 1; i < len(types); i++ {
54 if err := compare(regexes[0], regexes[i],
khenaidoo7585a962021-06-10 16:15:38 -040055 "../"+types[0]+"/cache.go",
56 "../"+types[i]+"/cache.go"); err != nil {
Kent Hagerman433a31a2020-05-20 19:04:48 -040057 t.Error(err)
58 return
59 }
60 }
61}
62
Kent Hagermanfa9d6d42020-05-25 11:49:40 -040063func compare(regexesA, regexesB []*regexp.Regexp, fileNameA, fileNameB string) error {
Andrey Pozolotin34dd63f2021-05-31 21:26:40 +030064 fileA, err := os.Open(filepath.Clean(fileNameA))
Kent Hagerman433a31a2020-05-20 19:04:48 -040065 if err != nil {
66 return err
67 }
Andrey Pozolotin34dd63f2021-05-31 21:26:40 +030068 defer func() {
69 err := fileA.Close()
70 if err != nil {
71 logger.Errorf(context.Background(), "failed to close file: %v", err)
72 }
73 }()
Kent Hagerman433a31a2020-05-20 19:04:48 -040074
Andrey Pozolotin34dd63f2021-05-31 21:26:40 +030075 fileB, err := os.Open(filepath.Clean(fileNameB))
Kent Hagerman433a31a2020-05-20 19:04:48 -040076 if err != nil {
77 return err
78 }
Andrey Pozolotin34dd63f2021-05-31 21:26:40 +030079 defer func() {
80 err := fileB.Close()
81 if err != nil {
82 logger.Errorf(context.Background(), "failed to close file: %v", err)
83 }
84 }()
Kent Hagerman433a31a2020-05-20 19:04:48 -040085
86 scannerA, scannerB := bufio.NewScanner(fileA), bufio.NewScanner(fileB)
87
Kent Hagermanfa9d6d42020-05-25 11:49:40 -040088 // treat any number of spaces as a single space
89 spaceRegex := regexp.MustCompile(` +`)
90 // extra lines are permitted before a "blank" line, or before a lock/unlock
91 spacerRegex := regexp.MustCompile(`^(?:[^a-z]*|.*Lock\(\)|.*Unlock\(\))$`)
92 // ignore import type differences
93 libGoImportRegex := regexp.MustCompile(`^.*github\.com/opencord/voltha-protos/.*$`)
Kent Hagerman433a31a2020-05-20 19:04:48 -040094
Kent Hagermanfa9d6d42020-05-25 11:49:40 -040095 lineA, lineB := 1, 1
96linesLoop:
Kent Hagerman433a31a2020-05-20 19:04:48 -040097 for {
Kent Hagermanfa9d6d42020-05-25 11:49:40 -040098 if continueA, continueB := scannerA.Scan(), scannerB.Scan(); !continueA || !continueB {
99 // EOF
100 break linesLoop
101 }
102 textA, textB := scannerA.Text(), scannerB.Text()
103
104 // allow any number of "extra" lines just before a spacer line
105 for {
106 isSpacerA, isSpacerB := spacerRegex.MatchString(textA), spacerRegex.MatchString(textB)
107 if isSpacerA && !isSpacerB {
108 if !scannerB.Scan() {
109 // EOF
110 break linesLoop
Kent Hagerman433a31a2020-05-20 19:04:48 -0400111 }
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400112 lineB++
113 textB = scannerB.Text()
114 continue
115 } else if isSpacerB && !isSpacerA {
116 if !scannerA.Scan() {
117 // EOF
118 break linesLoop
Kent Hagerman433a31a2020-05-20 19:04:48 -0400119 }
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400120 lineA++
121 textA = scannerA.Text()
122 continue
Kent Hagerman433a31a2020-05-20 19:04:48 -0400123 }
Kent Hagerman433a31a2020-05-20 19:04:48 -0400124 break
125 }
126
Kent Hagerman433a31a2020-05-20 19:04:48 -0400127 replacedA, replacedB := textA, textB
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400128 for i := range regexesA {
Kent Hagerman433a31a2020-05-20 19:04:48 -0400129 replacement := "{{type" + strconv.Itoa(i) + "}}"
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400130 replacedA, replacedB = regexesA[i].ReplaceAllString(replacedA, replacement), regexesB[i].ReplaceAllString(replacedB, replacement)
Kent Hagerman433a31a2020-05-20 19:04:48 -0400131 }
132
133 // replace multiple spaces with single space
134 replacedA, replacedB = spaceRegex.ReplaceAllString(replacedA, " "), spaceRegex.ReplaceAllString(replacedB, " ")
135
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400136 // ignore voltha-protos import of ofp vs voltha
137 replacedA, replacedB = libGoImportRegex.ReplaceAllString(replacedA, "{{lib-go-import}}"), libGoImportRegex.ReplaceAllString(replacedB, "{{lib-go-import}}")
138
139 if replacedA != replacedB && textA != textB {
140 return fmt.Errorf("files which must be identical do not match: \n %s:%d\n %s\n %s:%d\n %s\n\n\t%s\n\t%s", fileNameA, lineA, textA, fileNameB, lineB, textB, replacedA, replacedB)
Kent Hagerman433a31a2020-05-20 19:04:48 -0400141 }
142
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400143 lineA++
144 lineB++
Kent Hagerman433a31a2020-05-20 19:04:48 -0400145 }
146
147 if err := scannerA.Err(); err != nil {
148 return err
149 }
150 if err := scannerB.Err(); err != nil {
151 return err
152 }
153 return nil
154}