github.com/GoogleCloudPlatform/testgrid@v0.0.174/metadata/junit/junit_test.go (about)

     1  /*
     2  Copyright 2020 The TestGrid Authors.
     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  
    17  package junit
    18  
    19  import (
    20  	"bytes"
    21  	"encoding/xml"
    22  	"testing"
    23  
    24  	"github.com/google/go-cmp/cmp"
    25  )
    26  
    27  func TestMessage(t *testing.T) {
    28  	pstr := func(s string) *string {
    29  		return &s
    30  	}
    31  
    32  	cases := []struct {
    33  		name     string
    34  		jr       Result
    35  		max      int
    36  		expected string
    37  	}{
    38  		{
    39  			name: "basically works",
    40  		},
    41  		{
    42  			name: "errored takes top priority with message and value",
    43  			jr: Result{
    44  				Errored: &Errored{Message: "errored-0-msg", Value: *pstr("errored-0")},
    45  				Failure: &Failure{Message: "failure-1-msg", Value: *pstr("failure-1")},
    46  				Skipped: &Skipped{Message: "skipped-2-msg", Value: *pstr("skipped-2")},
    47  				Error:   pstr("error-3"),
    48  				Output:  pstr("output-4"),
    49  			},
    50  			expected: "errored-0-msg\nerrored-0",
    51  		},
    52  		{
    53  			name: "errored takes top priority with message",
    54  			jr: Result{
    55  				Errored: &Errored{Message: "errored-0-msg"},
    56  				Failure: &Failure{Message: "failure-1-msg"},
    57  				Skipped: &Skipped{Message: "skipped-2-msg"},
    58  				Error:   pstr("error-3"),
    59  				Output:  pstr("output-4"),
    60  			},
    61  			expected: "errored-0-msg",
    62  		},
    63  		{
    64  			name: "errored takes top priority with value",
    65  			jr: Result{
    66  				Errored: &Errored{Value: *pstr("errored-0")},
    67  				Failure: &Failure{Value: *pstr("failure-1")},
    68  				Skipped: &Skipped{Value: *pstr("skipped-2")},
    69  				Error:   pstr("error-3"),
    70  				Output:  pstr("output-4"),
    71  			},
    72  			expected: "errored-0",
    73  		},
    74  
    75  		{
    76  			name: "failure priorized over skipped, error and output with message and value",
    77  			jr: Result{
    78  				Failure: &Failure{Message: "failure-0-msg", Value: *pstr("failure-0")},
    79  				Skipped: &Skipped{Message: "skipped-1-msg", Value: *pstr("skipped-1")},
    80  				Error:   pstr("error-2"),
    81  				Output:  pstr("output-3"),
    82  			},
    83  			expected: "failure-0-msg\nfailure-0",
    84  		},
    85  		{
    86  			name: "failure priorized over skipped, error and output with message",
    87  			jr: Result{
    88  				Failure: &Failure{Message: "failure-0-msg"},
    89  				Skipped: &Skipped{Message: "skipped-1-msg"},
    90  				Error:   pstr("error-2"),
    91  				Output:  pstr("output-3"),
    92  			},
    93  			expected: "failure-0-msg",
    94  		},
    95  		{
    96  			name: "failure priorized over skipped, error and output with value",
    97  			jr: Result{
    98  				Failure: &Failure{Value: *pstr("failure-0")},
    99  				Skipped: &Skipped{Value: *pstr("skipped-1")},
   100  				Error:   pstr("error-2"),
   101  				Output:  pstr("output-3"),
   102  			},
   103  			expected: "failure-0",
   104  		},
   105  		{
   106  			name: "skipped prioritized over error, output with message and value",
   107  			jr: Result{
   108  				Skipped: &Skipped{Message: "skipped-1-msg", Value: *pstr("skipped-1")},
   109  				Error:   pstr("error-2"),
   110  				Output:  pstr("output-3"),
   111  			},
   112  			expected: "skipped-1-msg\nskipped-1",
   113  		},
   114  		{
   115  			name: "skipped prioritized over error, output with message",
   116  			jr: Result{
   117  				Skipped: &Skipped{Message: "skipped-1-msg"},
   118  				Error:   pstr("error-2"),
   119  				Output:  pstr("output-3"),
   120  			},
   121  			expected: "skipped-1-msg",
   122  		},
   123  		{
   124  			name: "skipped prioritized over error, output with value",
   125  			jr: Result{
   126  				Skipped: &Skipped{Value: *pstr("skipped-1")},
   127  				Error:   pstr("error-2"),
   128  				Output:  pstr("output-3"),
   129  			},
   130  			expected: "skipped-1",
   131  		},
   132  		{
   133  			name: "error has higher priority than output",
   134  			jr: Result{
   135  				Error:  pstr("error-2"),
   136  				Output: pstr("output-3"),
   137  			},
   138  			expected: "error-2",
   139  		},
   140  		{
   141  			name: "return output when set",
   142  			jr: Result{
   143  				Output: pstr("output-3"),
   144  			},
   145  			expected: "output-3",
   146  		},
   147  		{
   148  			name: "truncate long messages upon request",
   149  			jr: Result{
   150  				Output: pstr("four by four"),
   151  			},
   152  			max:      8,
   153  			expected: "four...four",
   154  		},
   155  		{
   156  			name: "handle invalid UTF-8 strings",
   157  			jr: Result{
   158  				Output: pstr("a\xc5z"),
   159  			},
   160  			max:      8,
   161  			expected: "invalid utf8: a?z",
   162  		},
   163  	}
   164  
   165  	for _, tc := range cases {
   166  		t.Run(tc.name, func(t *testing.T) {
   167  			if actual, expected := tc.jr.Message(tc.max), tc.expected; actual != expected {
   168  				t.Errorf("jr.Message(%d) got %q, want %q", tc.max, actual, expected)
   169  			}
   170  		})
   171  	}
   172  }
   173  
   174  func TestParse(t *testing.T) {
   175  	pstr := func(s string) *string {
   176  		return &s
   177  	}
   178  	cases := []struct {
   179  		name     string
   180  		buf      []byte
   181  		expected *Suites
   182  	}{
   183  		{
   184  			name:     "parse empty file as empty suite",
   185  			expected: &Suites{},
   186  		},
   187  		{
   188  			name: "not xml fails",
   189  			buf:  []byte("<hello"),
   190  		},
   191  		{
   192  			name: "parse testsuite correctly",
   193  			buf:  []byte(`<testsuite><testcase name="hi"/></testsuite>`),
   194  			expected: &Suites{
   195  				Suites: []Suite{
   196  					{
   197  						XMLName: xml.Name{Local: "testsuite"},
   198  						Results: []Result{
   199  							{Name: "hi"},
   200  						},
   201  					},
   202  				},
   203  			},
   204  		},
   205  		{
   206  			name: "parse testsuites correctly",
   207  			buf: []byte(`
   208                          <testsuites>
   209                              <testsuite name="fun" tests="10" disabled="1" skipped="2" errors="3" failures="4" time="100.1" timestamp="2023-08-28T17:15:04">
   210                                  <testsuite name="knee">
   211  				    <properties>
   212  					<property name="SuiteSucceeded" value="true"></property>
   213                                      </properties>
   214                                      <testcase name="bone" time="6" />
   215                                      <testcase name="head" time="3" >
   216  										<failure type="failure" message="failure message attribute"> failure message body </failure>
   217  									</testcase>
   218                                      <testcase name="neck" time="2" >
   219  										<error type="error" message="error message attribute"> error message body </error>
   220  									</testcase>
   221                                  </testsuite>
   222  				<testcase name="word"  classname="E2E Suite" status="skipped" time="7"></testcase>
   223                              </testsuite>
   224                          </testsuites>
   225                          `),
   226  			expected: &Suites{
   227  				XMLName: xml.Name{Local: "testsuites"},
   228  				Suites: []Suite{
   229  					{
   230  						XMLName:   xml.Name{Local: "testsuite"},
   231  						Name:      "fun",
   232  						Failures:  4,
   233  						Tests:     10,
   234  						Disabled:  1,
   235  						Skipped:   2,
   236  						Errors:    3,
   237  						Time:      100.1,
   238  						TimeStamp: "2023-08-28T17:15:04",
   239  						Suites: []Suite{
   240  							{
   241  								XMLName: xml.Name{Local: "testsuite"},
   242  								Name:    "knee",
   243  								Properties: &Properties{
   244  									[]Property{
   245  										{
   246  											Name:  "SuiteSucceeded",
   247  											Value: "true",
   248  										},
   249  									},
   250  								},
   251  								Results: []Result{
   252  									{
   253  										Name: "bone",
   254  										Time: 6,
   255  									},
   256  									{
   257  										Name:    "head",
   258  										Time:    3,
   259  										Failure: &Failure{Type: "failure", Message: "failure message attribute", Value: *pstr(" failure message body ")},
   260  									},
   261  									{
   262  										Name:    "neck",
   263  										Time:    2,
   264  										Errored: &Errored{Type: "error", Message: "error message attribute", Value: *pstr(" error message body ")},
   265  									},
   266  								},
   267  							},
   268  						},
   269  						Results: []Result{
   270  							{
   271  								Name:      "word",
   272  								Time:      7,
   273  								ClassName: "E2E Suite",
   274  								Status:    "skipped",
   275  							},
   276  						},
   277  					},
   278  				},
   279  			},
   280  		},
   281  	}
   282  
   283  	for _, tc := range cases {
   284  		t.Run(tc.name, func(t *testing.T) {
   285  			actual, err := Parse(tc.buf)
   286  			str := string(tc.buf)
   287  			switch {
   288  			case err != nil:
   289  				if tc.expected != nil {
   290  					t.Errorf("Parse(%q) got unexpected error: %v", str, err)
   291  				}
   292  			case tc.expected == nil:
   293  				t.Errorf("Parse(%q) got %v, wanted an error", str, actual)
   294  			default:
   295  				if diff := cmp.Diff(actual, tc.expected); diff != "" {
   296  					t.Errorf("Parse(%q) got unexpected diff:\n%s", str, diff)
   297  				}
   298  			}
   299  			if err == nil {
   300  				streamActual, err := ParseStream(bytes.NewReader(tc.buf))
   301  				if err != nil {
   302  					t.Errorf("ParseStream() got unexpected error: %v", err)
   303  				}
   304  				if diff := cmp.Diff(actual, streamActual); diff != "" {
   305  					t.Errorf("ParseStream() got unexpected diff:\n%s", diff)
   306  				}
   307  			}
   308  		})
   309  	}
   310  }