github.com/Financial-Times/publish-availability-monitor@v1.12.0/checks/publishCheck_test.go (about)

     1  package checks
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"io"
     7  	"net/http"
     8  	"net/url"
     9  	"testing"
    10  	"time"
    11  
    12  	"github.com/Financial-Times/go-logger/v2"
    13  	"github.com/Financial-Times/publish-availability-monitor/httpcaller"
    14  	"github.com/Financial-Times/publish-availability-monitor/metrics"
    15  	"github.com/stretchr/testify/assert"
    16  )
    17  
    18  func TestIsCurrentOperationFinished_ContentCheck_InvalidContent(t *testing.T) {
    19  	currentTid := "tid_1234"
    20  	testResponse := `{ "uuid" : "1234-1234"`
    21  	response := buildResponse(200, testResponse)
    22  	defer response.Body.Close()
    23  	contentCheck := &ContentCheck{
    24  		mockHTTPCaller(t, "tid_pam_1234", response),
    25  	}
    26  	log := logger.NewUPPLogger("test", "PANIC")
    27  
    28  	pm := newPublishMetricBuilder().withTID(currentTid).build()
    29  	finished, _ := contentCheck.isCurrentOperationFinished(NewPublishCheck(
    30  		pm,
    31  		"",
    32  		"",
    33  		0,
    34  		0,
    35  		nil,
    36  		nil,
    37  		log,
    38  	))
    39  	assert.False(t, finished, "Expected error.")
    40  }
    41  
    42  func TestIsCurrentOperationFinished_ContentCheck_Finished(t *testing.T) {
    43  	currentTid := "tid_1234"
    44  	testResponse := fmt.Sprintf(`{ "uuid" : "1234-1234", "publishReference" : "%s"}`, currentTid)
    45  	response := buildResponse(200, testResponse)
    46  	defer response.Body.Close()
    47  	contentCheck := &ContentCheck{
    48  		mockHTTPCaller(t, "tid_pam_1234", response),
    49  	}
    50  	log := logger.NewUPPLogger("test", "PANIC")
    51  
    52  	pm := newPublishMetricBuilder().withTID(currentTid).build()
    53  	finished, _ := contentCheck.isCurrentOperationFinished(NewPublishCheck(
    54  		pm,
    55  		"",
    56  		"",
    57  		0,
    58  		0,
    59  		nil,
    60  		nil,
    61  		log,
    62  	))
    63  	assert.True(t, finished, "operation should have finished successfully")
    64  }
    65  
    66  func TestIsCurrentOperationFinished_ContentCheck_WithAuthentication(t *testing.T) {
    67  	currentTid := "tid_5678"
    68  	testResponse := fmt.Sprintf(`{ "uuid" : "1234-1234", "publishReference" : "%s"}`, currentTid)
    69  	username := "jdoe"
    70  	password := "frodo"
    71  	response := buildResponse(200, testResponse)
    72  	defer response.Body.Close()
    73  	contentCheck := &ContentCheck{
    74  		mockAuthenticatedHTTPCaller(t, "tid_pam_5678", username, password, response),
    75  	}
    76  	log := logger.NewUPPLogger("test", "PANIC")
    77  
    78  	pm := newPublishMetricBuilder().withTID(currentTid).build()
    79  	finished, _ := contentCheck.isCurrentOperationFinished(NewPublishCheck(
    80  		pm,
    81  		username,
    82  		password,
    83  		0,
    84  		0,
    85  		nil,
    86  		nil,
    87  		log,
    88  	))
    89  	assert.True(t, finished, "operation should have finished successfully")
    90  }
    91  
    92  func TestIsCurrentOperationFinished_ContentCheck_NotFinished(t *testing.T) {
    93  	currentTid := "tid_1234"
    94  	testResponse := `{ "uuid" : "1234-1234", "publishReference" : "tid_1235"}`
    95  	response := buildResponse(200, testResponse)
    96  	defer response.Body.Close()
    97  	contentCheck := &ContentCheck{
    98  		mockHTTPCaller(t, "tid_pam_1234", response),
    99  	}
   100  	log := logger.NewUPPLogger("test", "PANIC")
   101  
   102  	pm := newPublishMetricBuilder().withTID(currentTid).build()
   103  	finished, _ := contentCheck.isCurrentOperationFinished(NewPublishCheck(
   104  		pm,
   105  		"",
   106  		"",
   107  		0,
   108  		0,
   109  		nil,
   110  		nil,
   111  		log,
   112  	))
   113  	assert.False(t, finished, "Expected failure.")
   114  }
   115  
   116  func TestIsCurrentOperationFinished_ContentCheck_MarkedDeleted_Finished(t *testing.T) {
   117  	currentTid := "tid_1234"
   118  	testResponse := fmt.Sprintf(`{ "uuid" : "1234-1234", "publishReference" : "%s"}`, currentTid)
   119  	response := buildResponse(404, testResponse)
   120  	defer response.Body.Close()
   121  	contentCheck := &ContentCheck{
   122  		mockHTTPCaller(t, "tid_pam_1234", response),
   123  	}
   124  	log := logger.NewUPPLogger("test", "PANIC")
   125  
   126  	pm := newPublishMetricBuilder().withTID(currentTid).withMarkedDeleted(true).build()
   127  	finished, _ := contentCheck.isCurrentOperationFinished(NewPublishCheck(
   128  		pm,
   129  		"",
   130  		"",
   131  		0,
   132  		0,
   133  		nil,
   134  		nil,
   135  		log,
   136  	))
   137  	assert.True(t, finished, "operation should have finished successfully.")
   138  }
   139  
   140  func TestIsCurrentOperationFinished_ContentCheck_MarkedDeleted_NotFinished(t *testing.T) {
   141  	currentTid := "tid_1234"
   142  	testResponse := fmt.Sprintf(`{ "uuid" : "1234-1234", "publishReference" : "%s"}`, currentTid)
   143  	response := buildResponse(200, testResponse)
   144  	defer response.Body.Close()
   145  	contentCheck := &ContentCheck{
   146  		mockHTTPCaller(t, "tid_pam_1234", response),
   147  	}
   148  	log := logger.NewUPPLogger("test", "PANIC")
   149  
   150  	pm := newPublishMetricBuilder().withTID(currentTid).withMarkedDeleted(true).build()
   151  	finished, _ := contentCheck.isCurrentOperationFinished(NewPublishCheck(
   152  		pm,
   153  		"",
   154  		"",
   155  		0,
   156  		0,
   157  		nil,
   158  		nil,
   159  		log,
   160  	))
   161  	assert.False(t, finished, "operation should not have finished")
   162  }
   163  
   164  func TestIsCurrentOperationFinished_ContentCheck_LastModifiedDateIsAfterCurrentPublishDate_IgnoreCheckTrue(t *testing.T) {
   165  	currentTid := "tid_1234"
   166  	publishDate, err := time.Parse(DateLayout, "2016-01-08T14:22:06.271Z")
   167  	assert.Nil(t, err, "Failure in setting up test data")
   168  
   169  	testResponse := `{ "uuid" : "1234-1234", "publishReference" : "tid_1235", "lastModified" : "2016-01-08T14:22:07.391Z" }`
   170  	response := buildResponse(200, testResponse)
   171  	defer response.Body.Close()
   172  	contentCheck := &ContentCheck{
   173  		mockHTTPCaller(t, "tid_pam_1234", response),
   174  	}
   175  	log := logger.NewUPPLogger("test", "PANIC")
   176  
   177  	pm := newPublishMetricBuilder().withTID(currentTid).withPublishDate(publishDate).build()
   178  	_, ignoreCheck := contentCheck.isCurrentOperationFinished(NewPublishCheck(
   179  		pm,
   180  		"",
   181  		"",
   182  		0,
   183  		0,
   184  		nil,
   185  		nil,
   186  		log,
   187  	))
   188  	assert.True(t, ignoreCheck, "check should be ignored")
   189  }
   190  
   191  // fails for dateLayout="2006-01-02T15:04:05.000Z"
   192  func TestIsCurrentOperationFinished_ContentCheck_LastModifiedDateIsBeforeCurrentPublishDateSpecifiedWith2Decimals_IgnoreCheckFalse(t *testing.T) {
   193  	currentTid := "tid_1234"
   194  
   195  	publishDate, err := time.Parse(DateLayout, "2016-02-01T14:30:21.55Z")
   196  	assert.Nil(t, err, "Failure in setting up test data")
   197  
   198  	testResponse := `{ "uuid" : "1234-1234", "publishReference" : "tid_1235", "lastModified" : "2016-02-01T14:30:21.549Z" }`
   199  	response := buildResponse(200, testResponse)
   200  	defer response.Body.Close()
   201  	contentCheck := &ContentCheck{
   202  		mockHTTPCaller(t, "tid_pam_1234", response),
   203  	}
   204  	log := logger.NewUPPLogger("test", "PANIC")
   205  
   206  	pm := newPublishMetricBuilder().withTID(currentTid).withPublishDate(publishDate).build()
   207  	_, ignoreCheck := contentCheck.isCurrentOperationFinished(NewPublishCheck(
   208  		pm,
   209  		"",
   210  		"",
   211  		0,
   212  		0,
   213  		nil,
   214  		nil,
   215  		log,
   216  	))
   217  	assert.False(t, ignoreCheck, "check should not be ignored")
   218  }
   219  
   220  func TestIsCurrentOperationFinished_ContentCheck_LastModifiedDateIsBeforeCurrentPublishDate_IgnoreCheckFalse(t *testing.T) {
   221  	currentTid := "tid_1234"
   222  	publishDate, err := time.Parse(DateLayout, "2016-01-08T14:22:06.271Z")
   223  	assert.Nil(t, err, "Failure in setting up test data")
   224  
   225  	testResponse := `{ "uuid" : "1234-1234", "publishReference" : "tid_1235", "lastModified" : "2016-01-08T14:22:05.391Z" }`
   226  	response := buildResponse(200, testResponse)
   227  	defer response.Body.Close()
   228  	contentCheck := &ContentCheck{
   229  		mockHTTPCaller(t, "tid_pam_1234", response),
   230  	}
   231  	log := logger.NewUPPLogger("test", "PANIC")
   232  
   233  	pm := newPublishMetricBuilder().withTID(currentTid).withPublishDate(publishDate).build()
   234  	_, ignoreCheck := contentCheck.isCurrentOperationFinished(NewPublishCheck(
   235  		pm,
   236  		"",
   237  		"",
   238  		0,
   239  		0,
   240  		nil,
   241  		nil,
   242  		log,
   243  	))
   244  	assert.False(t, ignoreCheck, "check should not be ignored")
   245  }
   246  
   247  func TestIsCurrentOperationFinished_ContentCheck_LastModifiedDateIsBeforeCurrentPublishDate_NotFinished(t *testing.T) {
   248  	currentTid := "tid_1234"
   249  	publishDate, err := time.Parse(DateLayout, "2016-01-08T14:22:06.271Z")
   250  	assert.Nil(t, err, "Failure in setting up test data")
   251  
   252  	testResponse := `{ "uuid" : "1234-1234", "publishReference" : "tid_1235", "lastModified" : "2016-01-08T14:22:05.391Z" }`
   253  	response := buildResponse(200, testResponse)
   254  	defer response.Body.Close()
   255  	contentCheck := &ContentCheck{
   256  		mockHTTPCaller(t, "tid_pam_1234", response),
   257  	}
   258  	log := logger.NewUPPLogger("test", "PANIC")
   259  
   260  	pm := newPublishMetricBuilder().withTID(currentTid).withPublishDate(publishDate).build()
   261  	finished, _ := contentCheck.isCurrentOperationFinished(NewPublishCheck(
   262  		pm,
   263  		"",
   264  		"",
   265  		0,
   266  		0,
   267  		nil,
   268  		nil,
   269  		log,
   270  	))
   271  	assert.False(t, finished, "operation should not have finished")
   272  }
   273  
   274  func TestIsCurrentOperationFinished_ContentCheck_LastModifiedDateEqualsCurrentPublishDate_Finished(t *testing.T) {
   275  	currentTid := "tid_1234"
   276  	publishDateAsString := "2016-01-08T14:22:06.271Z"
   277  	publishDate, err := time.Parse(DateLayout, publishDateAsString)
   278  	assert.Nil(t, err, "Failure in setting up test data")
   279  
   280  	testResponse := fmt.Sprintf(`{ "uuid" : "1234-1234", "publishReference" : "%s", "lastModified" : "%s" }`, currentTid, publishDateAsString)
   281  	response := buildResponse(200, testResponse)
   282  	defer response.Body.Close()
   283  	contentCheck := &ContentCheck{
   284  		mockHTTPCaller(t, "tid_pam_1234", response),
   285  	}
   286  	log := logger.NewUPPLogger("test", "PANIC")
   287  
   288  	pm := newPublishMetricBuilder().withTID(currentTid).withPublishDate(publishDate).build()
   289  	finished, _ := contentCheck.isCurrentOperationFinished(NewPublishCheck(
   290  		pm,
   291  		"",
   292  		"",
   293  		0,
   294  		0,
   295  		nil,
   296  		nil,
   297  		log,
   298  	))
   299  	assert.True(t, finished, "operation should have finished successfully")
   300  }
   301  
   302  // fallback to publish reference check if last modified date is not valid
   303  func TestIsCurrentOperationFinished_ContentCheck_LastModifiedDateIsNullCurrentTIDAndPubReferenceMatch_Finished(t *testing.T) {
   304  	currentTid := "tid_1234"
   305  	publishDate, err := time.Parse(DateLayout, "2016-01-08T14:22:06.271Z")
   306  	assert.Nil(t, err, "Failure in setting up test data")
   307  
   308  	testResponse := fmt.Sprintf(`{ "uuid" : "1234-1234", "publishReference" : "%s", "lastModified" : null }`, currentTid)
   309  	response := buildResponse(200, testResponse)
   310  	defer response.Body.Close()
   311  	contentCheck := &ContentCheck{
   312  		mockHTTPCaller(t, "tid_pam_1234", response),
   313  	}
   314  	log := logger.NewUPPLogger("test", "PANIC")
   315  
   316  	pm := newPublishMetricBuilder().withTID(currentTid).withPublishDate(publishDate).build()
   317  	finished, _ := contentCheck.isCurrentOperationFinished(NewPublishCheck(
   318  		pm,
   319  		"",
   320  		"",
   321  		0,
   322  		0,
   323  		nil,
   324  		nil,
   325  		log,
   326  	))
   327  	assert.True(t, finished, "operation should have finished successfully")
   328  }
   329  
   330  // fallback to publish reference check if last modified date is not valid
   331  func TestIsCurrentOperationFinished_ContentCheck_LastModifiedDateIsEmptyStringCurrentTIDAndPubReferenceMatch_Finished(t *testing.T) {
   332  	currentTid := "tid_1234"
   333  	publishDate, err := time.Parse(DateLayout, "2016-01-08T14:22:06.271Z")
   334  	assert.Nil(t, err, "Failure in setting up test data")
   335  
   336  	testResponse := fmt.Sprintf(`{ "uuid" : "1234-1234", "publishReference" : "%s", "lastModified" : "" }`, currentTid)
   337  	response := buildResponse(200, testResponse)
   338  	defer response.Body.Close()
   339  	contentCheck := &ContentCheck{
   340  		mockHTTPCaller(t, "tid_pam_1234", response),
   341  	}
   342  	log := logger.NewUPPLogger("test", "PANIC")
   343  
   344  	pm := newPublishMetricBuilder().withTID(currentTid).withPublishDate(publishDate).build()
   345  	finished, _ := contentCheck.isCurrentOperationFinished(NewPublishCheck(
   346  		pm,
   347  		"",
   348  		"",
   349  		0,
   350  		0,
   351  		nil,
   352  		nil,
   353  		log,
   354  	))
   355  	assert.True(t, finished, "operation should have finished successfully")
   356  }
   357  
   358  type publishMetricBuilder interface {
   359  	withUUID(string) publishMetricBuilder
   360  	withEndpoint(string) publishMetricBuilder
   361  	withPlatform(string) publishMetricBuilder
   362  	withTID(string) publishMetricBuilder
   363  	withMarkedDeleted(bool) publishMetricBuilder
   364  	withPublishDate(time.Time) publishMetricBuilder
   365  	build() metrics.PublishMetric
   366  }
   367  
   368  // PublishMetricBuilder implementation
   369  type pmBuilder struct {
   370  	UUID          string
   371  	endpoint      url.URL
   372  	platform      string
   373  	tid           string
   374  	markedDeleted bool
   375  	publishDate   time.Time
   376  }
   377  
   378  func (b *pmBuilder) withUUID(uuid string) publishMetricBuilder {
   379  	b.UUID = uuid
   380  	return b
   381  }
   382  
   383  func (b *pmBuilder) withEndpoint(endpoint string) publishMetricBuilder {
   384  	e, _ := url.Parse(endpoint)
   385  	b.endpoint = *e
   386  	return b
   387  }
   388  
   389  func (b *pmBuilder) withPlatform(platform string) publishMetricBuilder {
   390  	b.platform = platform
   391  	return b
   392  }
   393  
   394  func (b *pmBuilder) withTID(tid string) publishMetricBuilder {
   395  	b.tid = tid
   396  	return b
   397  }
   398  
   399  func (b *pmBuilder) withMarkedDeleted(markedDeleted bool) publishMetricBuilder {
   400  	b.markedDeleted = markedDeleted
   401  	return b
   402  }
   403  
   404  func (b *pmBuilder) withPublishDate(publishDate time.Time) publishMetricBuilder {
   405  	b.publishDate = publishDate
   406  	return b
   407  }
   408  
   409  func (b *pmBuilder) build() metrics.PublishMetric {
   410  	return metrics.PublishMetric{
   411  		UUID:            b.UUID,
   412  		Endpoint:        b.endpoint,
   413  		Platform:        b.platform,
   414  		TID:             b.tid,
   415  		IsMarkedDeleted: b.markedDeleted,
   416  		PublishDate:     b.publishDate,
   417  	}
   418  }
   419  
   420  func newPublishMetricBuilder() publishMetricBuilder {
   421  	return &pmBuilder{}
   422  }
   423  
   424  func buildResponse(statusCode int, content string) *http.Response {
   425  	return &http.Response{
   426  		StatusCode: statusCode,
   427  		Body:       io.NopCloser(bytes.NewBuffer([]byte(content))),
   428  	}
   429  }
   430  
   431  // mock httpCaller implementation
   432  type testHTTPCaller struct {
   433  	t             *testing.T
   434  	authUser      string
   435  	authPass      string
   436  	tid           string
   437  	mockResponses []*http.Response
   438  	current       int
   439  }
   440  
   441  // returns the mock responses of testHTTPCaller in order
   442  func (t *testHTTPCaller) DoCall(config httpcaller.Config) (*http.Response, error) {
   443  	if t.authUser != config.Username || t.authPass != config.Password {
   444  		return buildResponse(401, `{message: "Not authenticated"}`), nil
   445  	}
   446  
   447  	if t.tid != "" {
   448  		assert.Equal(t.t, t.tid, config.TID, "transaction id")
   449  	}
   450  
   451  	response := t.mockResponses[t.current]
   452  	t.current = (t.current + 1) % len(t.mockResponses)
   453  	return response, nil
   454  }
   455  
   456  // builds testHTTPCaller with the given mocked responses in the provided order
   457  func mockHTTPCaller(t *testing.T, tid string, responses ...*http.Response) httpcaller.Caller {
   458  	return &testHTTPCaller{t: t, tid: tid, mockResponses: responses}
   459  }
   460  
   461  // builds testHTTPCaller with the given mocked responses in the provided order
   462  func mockAuthenticatedHTTPCaller(t *testing.T, tid string, username string, password string, responses ...*http.Response) httpcaller.Caller {
   463  	return &testHTTPCaller{t: t, tid: tid, authUser: username, authPass: password, mockResponses: responses}
   464  }