github.com/rainforestapp/rainforest-cli@v2.12.0+incompatible/reporter_test.go (about)

     1  package main
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"io/ioutil"
     7  	"os"
     8  	"path/filepath"
     9  	"reflect"
    10  	"testing"
    11  	"time"
    12  
    13  	"log"
    14  
    15  	"github.com/rainforestapp/rainforest-cli/rainforest"
    16  	"github.com/urfave/cli"
    17  )
    18  
    19  func newFakeReporter() *reporter {
    20  	r := newReporter()
    21  
    22  	r.createJUnitReportSchema = func(*rainforest.RunDetails, reporterAPI) (*jUnitReportSchema, error) {
    23  		return &jUnitReportSchema{}, nil
    24  	}
    25  
    26  	r.writeJUnitReport = func(*jUnitReportSchema, *os.File) error {
    27  		return nil
    28  	}
    29  
    30  	r.getRunDetails = func(int, reporterAPI) (*rainforest.RunDetails, error) {
    31  		return &rainforest.RunDetails{}, nil
    32  	}
    33  
    34  	r.createOutputFile = func(path string) (*os.File, error) {
    35  		return os.NewFile(1, "test"), nil
    36  	}
    37  
    38  	return r
    39  }
    40  
    41  func TestReporterCreateReport_WithoutFlags(t *testing.T) {
    42  	// No Flags
    43  	r := newReporter()
    44  	c := newFakeContext(make(map[string]interface{}), cli.Args{})
    45  
    46  	err := r.createReport(c)
    47  
    48  	if err == nil {
    49  		t.Error("No error produced in reporter.reportForRun when Run ID is omitted")
    50  	} else {
    51  		if err.Error() != "No run ID argument found." {
    52  			t.Errorf("Unexpected error in reporter.reportForRun when Run ID is omitted: %v", err.Error())
    53  		}
    54  	}
    55  }
    56  
    57  func TestReporterCreateReport(t *testing.T) {
    58  	var expectedFileName string
    59  	var expectedRunID int
    60  
    61  	r := newFakeReporter()
    62  
    63  	r.getRunDetails = func(runID int, client reporterAPI) (*rainforest.RunDetails, error) {
    64  		runDetails := rainforest.RunDetails{}
    65  		if runID != expectedRunID {
    66  			t.Errorf("Unexpected run ID given to createJunitReport.\nExpected: %v\nActual: %v", expectedRunID, runID)
    67  			return &runDetails, fmt.Errorf("Test failed")
    68  		}
    69  
    70  		return &runDetails, nil
    71  	}
    72  
    73  	r.createOutputFile = func(path string) (*os.File, error) {
    74  		filename := filepath.Base(path)
    75  
    76  		if filename != expectedFileName {
    77  			t.Errorf("Unexpected filename given to createJunitReport.\nExpected: %v\nActual: %v", expectedFileName, filename)
    78  		}
    79  
    80  		return os.Create("myfilename.xml")
    81  	}
    82  
    83  	defer os.Remove("myfilename.xml")
    84  
    85  	testCases := []struct {
    86  		mappings map[string]interface{}
    87  		args     []string
    88  		runID    int
    89  		filename string
    90  	}{
    91  		{
    92  			mappings: map[string]interface{}{
    93  				"junit-file": "myfilename.xml",
    94  			},
    95  			args:     []string{"112233"},
    96  			runID:    112233,
    97  			filename: "myfilename.xml",
    98  		},
    99  		{
   100  			mappings: map[string]interface{}{
   101  				"junit-file": "myfilename.xml",
   102  				"run-id":     "112233",
   103  			},
   104  			args:     []string{},
   105  			runID:    112233,
   106  			filename: "myfilename.xml",
   107  		},
   108  	}
   109  
   110  	for _, testCase := range testCases {
   111  		c := newFakeContext(testCase.mappings, testCase.args)
   112  		expectedRunID = testCase.runID
   113  		expectedFileName = testCase.filename
   114  
   115  		log.SetOutput(ioutil.Discard)
   116  		defer log.SetOutput(os.Stdout)
   117  		err := r.createReport(c)
   118  		if err != nil {
   119  			t.Errorf("Unexpected error in reporter.createReport: %v", err.Error())
   120  		}
   121  	}
   122  }
   123  
   124  type fakeReporterAPI struct {
   125  	RunMappings map[int][]rainforest.RunTestDetails
   126  }
   127  
   128  func (api fakeReporterAPI) GetRunTestDetails(runID int, testID int) (*rainforest.RunTestDetails, error) {
   129  	runTests, ok := api.RunMappings[runID]
   130  	if !ok {
   131  		return nil, fmt.Errorf("No Run found with ID %v", runID)
   132  	}
   133  
   134  	for _, runTestDetails := range runTests {
   135  		if runTestDetails.ID == testID {
   136  			return &runTestDetails, nil
   137  		}
   138  	}
   139  
   140  	return nil, fmt.Errorf("No RunTest found with ID %v", testID)
   141  }
   142  
   143  func (api fakeReporterAPI) GetRunDetails(int) (*rainforest.RunDetails, error) {
   144  	// implement when needed
   145  	return nil, errStub
   146  }
   147  
   148  func newFakeReporterAPI(runID int, runTestDetails []rainforest.RunTestDetails) *fakeReporterAPI {
   149  	return &fakeReporterAPI{
   150  		RunMappings: map[int][]rainforest.RunTestDetails{
   151  			runID: runTestDetails,
   152  		},
   153  	}
   154  }
   155  
   156  func TestCreateJUnitReportSchema(t *testing.T) {
   157  	// Without failures
   158  	now := time.Now()
   159  	runDesc := "very descriptive description"
   160  	runRelease := "1a2b3c"
   161  	totalTests := 1
   162  	totalNoResultTests := 0
   163  	totalFailedTests := 0
   164  	stateName := "complete"
   165  
   166  	runDetails := rainforest.RunDetails{
   167  		ID:                 123,
   168  		Description:        runDesc,
   169  		Release:            runRelease,
   170  		TotalTests:         totalTests,
   171  		TotalNoResultTests: totalNoResultTests,
   172  		TotalFailedTests:   totalFailedTests,
   173  		StateDetails: rainforest.RunStateDetails{
   174  			Name:         stateName,
   175  			IsFinalState: true,
   176  		},
   177  		Timestamps: map[string]time.Time{
   178  			"created_at":  now.Add(-30 * time.Minute),
   179  			"in_progress": now.Add(-25 * time.Minute),
   180  			stateName:     now,
   181  		},
   182  		Tests: []rainforest.RunTestDetails{
   183  			{
   184  				Title:     "My test title",
   185  				CreatedAt: now.Add(-25 * time.Minute),
   186  				UpdatedAt: now,
   187  				Result:    "passed",
   188  			},
   189  		},
   190  	}
   191  
   192  	// Dummy API - should not be used when there are no failed tests
   193  	api := newFakeReporterAPI(-1, []rainforest.RunTestDetails{})
   194  
   195  	schema, err := createJUnitReportSchema(&runDetails, api)
   196  	if err != nil {
   197  		t.Errorf("Unexpected error returned by createJunitTestReportSchema: %v", err)
   198  	}
   199  
   200  	expectedSchema := jUnitReportSchema{
   201  		Name:     runDesc,
   202  		Errors:   totalNoResultTests,
   203  		Failures: totalFailedTests,
   204  		Tests:    totalTests,
   205  		Time:     30 * time.Minute.Seconds(),
   206  		TestCases: []jUnitTestReportSchema{
   207  			{
   208  				Name: runDetails.Tests[0].Title,
   209  				Time: 25 * time.Minute.Seconds(),
   210  			},
   211  		},
   212  	}
   213  
   214  	if !reflect.DeepEqual(expectedSchema, *schema) {
   215  		t.Error("Incorrect JUnitTestReportSchema returned by createJunitTestReportSchema")
   216  		t.Errorf("Expected: %#v", expectedSchema)
   217  		t.Errorf("Actual: %#v", schema)
   218  	}
   219  
   220  	// Run has no description
   221  	runDetails.Description = ""
   222  	schema, err = createJUnitReportSchema(&runDetails, api)
   223  	if err != nil {
   224  		t.Errorf(err.Error())
   225  	}
   226  
   227  	expectedSchemaName := fmt.Sprintf("Run #%v", runDetails.ID)
   228  	if schema.Name != expectedSchemaName {
   229  		t.Errorf("Unexpected schema name. Expected: %v. Got %v.", expectedSchemaName, schema.Name)
   230  	}
   231  
   232  	runDetails.Description = runDesc // add description to the run again for next tests
   233  
   234  	// With failures
   235  	failedBrowser := "chrome"
   236  	failedNote := "This note should appear"
   237  
   238  	runDetails.TotalFailedTests = 1
   239  
   240  	failedTest := rainforest.RunTestDetails{
   241  		ID:        999888,
   242  		Title:     "My failed test",
   243  		CreatedAt: now.Add(-25 * time.Minute),
   244  		UpdatedAt: now,
   245  		Result:    "failed",
   246  	}
   247  	runDetails.Tests = []rainforest.RunTestDetails{failedTest}
   248  
   249  	apiTests := []rainforest.RunTestDetails{
   250  		{
   251  			ID:        failedTest.ID,
   252  			Title:     failedTest.Title,
   253  			CreatedAt: failedTest.CreatedAt,
   254  			UpdatedAt: failedTest.UpdatedAt,
   255  			Result:    failedTest.Result,
   256  			Steps: []rainforest.RunStepDetails{
   257  				{
   258  					Browsers: []rainforest.RunBrowserDetails{
   259  						{
   260  							Name: failedBrowser,
   261  							Feedback: []rainforest.RunFeedback{
   262  								{
   263  									Result:      "failed",
   264  									JobState:    "approved",
   265  									FailureNote: failedNote,
   266  								},
   267  								{
   268  									Result:      "yes",
   269  									JobState:    "approved",
   270  									FailureNote: "This note should not appear",
   271  								},
   272  								{
   273  									Result:      "no",
   274  									JobState:    "rejected",
   275  									FailureNote: "This note should not appear either",
   276  								},
   277  							},
   278  						},
   279  					},
   280  				},
   281  			},
   282  		},
   283  	}
   284  
   285  	api = newFakeReporterAPI(runDetails.ID, apiTests)
   286  
   287  	expectedSchema.Failures = 1
   288  	expectedSchema.TestCases = []jUnitTestReportSchema{
   289  		{
   290  			Name: failedTest.Title,
   291  			Time: 25 * time.Minute.Seconds(),
   292  			Failures: []jUnitTestReportFailure{
   293  				{
   294  					Type:    failedBrowser,
   295  					Message: failedNote,
   296  				},
   297  			},
   298  		},
   299  	}
   300  
   301  	var out bytes.Buffer
   302  	log.SetOutput(&out)
   303  	schema, err = createJUnitReportSchema(&runDetails, api)
   304  	log.SetOutput(os.Stdout)
   305  
   306  	if err != nil {
   307  		t.Errorf("Unexpected error returned by createJunitTestReportSchema: %v", err)
   308  	}
   309  
   310  	if !reflect.DeepEqual(expectedSchema, *schema) {
   311  		t.Error("Incorrect JUnitTestReportSchema returned by createJunitTestReportSchema")
   312  		t.Errorf("Expected: %#v", expectedSchema)
   313  		t.Errorf("Actual: %#v", schema)
   314  	}
   315  
   316  	// Failures due to Rainforest overriding tester result
   317  	commentReason := "unexpected_popup"
   318  	comment := "Where did this pop up come from?"
   319  	apiTests = []rainforest.RunTestDetails{
   320  		{
   321  			ID:        failedTest.ID,
   322  			Title:     failedTest.Title,
   323  			CreatedAt: failedTest.CreatedAt,
   324  			UpdatedAt: failedTest.UpdatedAt,
   325  			Result:    failedTest.Result,
   326  			Steps: []rainforest.RunStepDetails{
   327  				{
   328  					Browsers: []rainforest.RunBrowserDetails{
   329  						{
   330  							Name: failedBrowser,
   331  							Feedback: []rainforest.RunFeedback{
   332  								{
   333  									Result:        "failed",
   334  									JobState:      "approved",
   335  									CommentReason: commentReason,
   336  									Comment:       comment,
   337  								},
   338  								{
   339  									Result:   "passed",
   340  									JobState: "approved",
   341  								},
   342  								{
   343  									Result:      "failed",
   344  									JobState:    "rejected",
   345  									FailureNote: "This note should not appear either",
   346  								},
   347  							},
   348  						},
   349  					},
   350  				},
   351  			},
   352  		},
   353  	}
   354  
   355  	api = newFakeReporterAPI(runDetails.ID, apiTests)
   356  
   357  	expectedSchema.TestCases = []jUnitTestReportSchema{
   358  		{
   359  			Name: failedTest.Title,
   360  			Time: 25 * time.Minute.Seconds(),
   361  			Failures: []jUnitTestReportFailure{
   362  				{
   363  					Type:    failedBrowser,
   364  					Message: fmt.Sprintf("%v: %v", commentReason, comment),
   365  				},
   366  			},
   367  		},
   368  	}
   369  
   370  	log.SetOutput(&out)
   371  	schema, err = createJUnitReportSchema(&runDetails, api)
   372  	log.SetOutput(os.Stdout)
   373  
   374  	if err != nil {
   375  		t.Errorf("Unexpected error returned by createJunitTestReportSchema: %v", err)
   376  	}
   377  
   378  	if !reflect.DeepEqual(expectedSchema, *schema) {
   379  		t.Error("Incorrect JUnitTestReportSchema returned by createJunitTestReportSchema")
   380  		t.Errorf("Expected: %#v", expectedSchema)
   381  		t.Errorf("Actual: %#v", schema)
   382  	}
   383  }