blob: 958124dcbd128f66054adadeaa33795fb6519b33 [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"
21 "fmt"
22 "os"
23 "regexp"
24 "strconv"
Kent Hagerman433a31a2020-05-20 19:04:48 -040025 "testing"
26)
27
28// TestLoadersIdentical ensures that the group, flow, and meter loaders always have an identical implementation.
29func TestLoadersIdentical(t *testing.T) {
Kent Hagerman2a07b862020-06-19 15:23:07 -040030 types := []string{"flow", "group", "meter", "port", "logical_port"}
Kent Hagermanfa9d6d42020-05-25 11:49:40 -040031
Kent Hagerman433a31a2020-05-20 19:04:48 -040032 identical := [][]string{
Kent Hagerman2a07b862020-06-19 15:23:07 -040033 {`ofp\.OfpFlowStats`, `ofp\.OfpGroupEntry`, `ofp\.OfpMeterEntry`, `voltha\.Port`, `voltha\.LogicalPort`},
34 {`\.Id`, `\.Desc\.GroupId`, `\.Config\.MeterId`, `\.PortNo`, `\.OfpPort\.PortNo`},
35 {`uint64`, `uint32`, `uint32`, `uint32`, `uint32`},
36 {`Flow`, `Group`, `Meter`, `Port`, `Port`},
37 {`flow`, `group`, `meter`, `port`, `port|logical_port`},
Kent Hagerman433a31a2020-05-20 19:04:48 -040038 }
39
Kent Hagermanfa9d6d42020-05-25 11:49:40 -040040 regexes := make([][]*regexp.Regexp, len(identical[0]))
41 for i := range regexes {
42 regexes[i] = make([]*regexp.Regexp, len(identical))
43 }
Kent Hagerman433a31a2020-05-20 19:04:48 -040044 for i, group := range identical {
Kent Hagermanfa9d6d42020-05-25 11:49:40 -040045 for j, regexStr := range group {
46 // convert from column-wise to row-wise for convenience
47 regexes[j][i] = regexp.MustCompile(regexStr)
48 }
Kent Hagerman433a31a2020-05-20 19:04:48 -040049 }
50
Kent Hagermanfa9d6d42020-05-25 11:49:40 -040051 for i := 1; i < len(types); i++ {
52 if err := compare(regexes[0], regexes[i],
53 "../"+types[0]+"/loader.go",
54 "../"+types[i]+"/loader.go"); err != nil {
Kent Hagerman433a31a2020-05-20 19:04:48 -040055 t.Error(err)
56 return
57 }
58 }
59}
60
Kent Hagermanfa9d6d42020-05-25 11:49:40 -040061func compare(regexesA, regexesB []*regexp.Regexp, fileNameA, fileNameB string) error {
Kent Hagerman433a31a2020-05-20 19:04:48 -040062 fileA, err := os.Open(fileNameA)
63 if err != nil {
64 return err
65 }
66 defer fileA.Close()
67
68 fileB, err := os.Open(fileNameB)
69 if err != nil {
70 return err
71 }
72 defer fileB.Close()
73
74 scannerA, scannerB := bufio.NewScanner(fileA), bufio.NewScanner(fileB)
75
Kent Hagermanfa9d6d42020-05-25 11:49:40 -040076 // treat any number of spaces as a single space
77 spaceRegex := regexp.MustCompile(` +`)
78 // extra lines are permitted before a "blank" line, or before a lock/unlock
79 spacerRegex := regexp.MustCompile(`^(?:[^a-z]*|.*Lock\(\)|.*Unlock\(\))$`)
80 // ignore import type differences
81 libGoImportRegex := regexp.MustCompile(`^.*github\.com/opencord/voltha-protos/.*$`)
Kent Hagerman433a31a2020-05-20 19:04:48 -040082
Kent Hagermanfa9d6d42020-05-25 11:49:40 -040083 lineA, lineB := 1, 1
84linesLoop:
Kent Hagerman433a31a2020-05-20 19:04:48 -040085 for {
Kent Hagermanfa9d6d42020-05-25 11:49:40 -040086 if continueA, continueB := scannerA.Scan(), scannerB.Scan(); !continueA || !continueB {
87 // EOF
88 break linesLoop
89 }
90 textA, textB := scannerA.Text(), scannerB.Text()
91
92 // allow any number of "extra" lines just before a spacer line
93 for {
94 isSpacerA, isSpacerB := spacerRegex.MatchString(textA), spacerRegex.MatchString(textB)
95 if isSpacerA && !isSpacerB {
96 if !scannerB.Scan() {
97 // EOF
98 break linesLoop
Kent Hagerman433a31a2020-05-20 19:04:48 -040099 }
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400100 lineB++
101 textB = scannerB.Text()
102 continue
103 } else if isSpacerB && !isSpacerA {
104 if !scannerA.Scan() {
105 // EOF
106 break linesLoop
Kent Hagerman433a31a2020-05-20 19:04:48 -0400107 }
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400108 lineA++
109 textA = scannerA.Text()
110 continue
Kent Hagerman433a31a2020-05-20 19:04:48 -0400111 }
Kent Hagerman433a31a2020-05-20 19:04:48 -0400112 break
113 }
114
Kent Hagerman433a31a2020-05-20 19:04:48 -0400115 replacedA, replacedB := textA, textB
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400116 for i := range regexesA {
Kent Hagerman433a31a2020-05-20 19:04:48 -0400117 replacement := "{{type" + strconv.Itoa(i) + "}}"
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400118 replacedA, replacedB = regexesA[i].ReplaceAllString(replacedA, replacement), regexesB[i].ReplaceAllString(replacedB, replacement)
Kent Hagerman433a31a2020-05-20 19:04:48 -0400119 }
120
121 // replace multiple spaces with single space
122 replacedA, replacedB = spaceRegex.ReplaceAllString(replacedA, " "), spaceRegex.ReplaceAllString(replacedB, " ")
123
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400124 // ignore voltha-protos import of ofp vs voltha
125 replacedA, replacedB = libGoImportRegex.ReplaceAllString(replacedA, "{{lib-go-import}}"), libGoImportRegex.ReplaceAllString(replacedB, "{{lib-go-import}}")
126
127 if replacedA != replacedB && textA != textB {
128 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 -0400129 }
130
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400131 lineA++
132 lineB++
Kent Hagerman433a31a2020-05-20 19:04:48 -0400133 }
134
135 if err := scannerA.Err(); err != nil {
136 return err
137 }
138 if err := scannerB.Err(); err != nil {
139 return err
140 }
141 return nil
142}