github.com/decred/politeia@v1.4.0/politeiawww/legacy/codetracker/github/database/cockroachdb/cockroachdb_test.go (about)

     1  // Copyright (c) 2020 The Decred developers
     2  // Use of this source code is governed by an ISC
     3  // license that can be found in the LICENSE file.
     4  
     5  package cockroachdb
     6  
     7  import (
     8  	"regexp"
     9  	"strconv"
    10  	"testing"
    11  	"time"
    12  
    13  	"github.com/DATA-DOG/go-sqlmock"
    14  	"github.com/decred/politeia/politeiawww/legacy/codetracker/github/database"
    15  	"github.com/jinzhu/gorm"
    16  	_ "github.com/jinzhu/gorm/dialects/postgres"
    17  )
    18  
    19  func setupTestDB(t *testing.T) (*cockroachdb, sqlmock.Sqlmock, func()) {
    20  	t.Helper()
    21  
    22  	db, mock, err := sqlmock.New()
    23  	if err != nil {
    24  		t.Fatalf("error %s while creating stub db conn", err)
    25  	}
    26  
    27  	gdb, err := gorm.Open("postgres", db)
    28  	if err != nil {
    29  		t.Fatalf("error %s while opening db with gorm", err)
    30  	}
    31  
    32  	c := &cockroachdb{
    33  		recordsdb: gdb,
    34  	}
    35  
    36  	return c, mock, func() {
    37  		db.Close()
    38  	}
    39  }
    40  
    41  // Tests
    42  func TestNewPullRequests(t *testing.T) {
    43  	cdb, mock, close := setupTestDB(t)
    44  	defer close()
    45  
    46  	now := time.Now()
    47  	// Arguments
    48  	id := "https://github.com/decred/github/pull/1" +
    49  		strconv.Itoa(int(now.Unix()))
    50  	pr := &database.PullRequest{
    51  		ID:           id,
    52  		Repo:         "github",
    53  		Organization: "decred",
    54  		URL:          "https://github.com/decred/github/pull/1",
    55  		Number:       1,
    56  		User:         "stakey",
    57  		UpdatedAt:    now.Unix(),
    58  		ClosedAt:     now.Unix(),
    59  		MergedAt:     now.Unix(),
    60  		Merged:       true,
    61  		State:        "MERGED",
    62  		Additions:    100,
    63  		Deletions:    99,
    64  		MergedBy:     "davec",
    65  	}
    66  
    67  	// Queries
    68  	sqlInsertPullRequests := `INSERT INTO "pullrequests" ` +
    69  		`("id","repo","organization","url","number","author","updated_at",` +
    70  		`"closed_at","merged_at","merged","state","additions","deletions",` +
    71  		`"merged_by") ` +
    72  		`VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14) ` +
    73  		`RETURNING "pullrequests"."id"`
    74  
    75  	// Success Expectations
    76  	mock.ExpectBegin()
    77  	// Insert user to db
    78  	mock.ExpectQuery(regexp.QuoteMeta(sqlInsertPullRequests)).
    79  		WithArgs(
    80  			pr.ID,
    81  			pr.Repo,
    82  			pr.Organization,
    83  			pr.URL,
    84  			pr.Number,
    85  			pr.User,
    86  			pr.UpdatedAt,
    87  			pr.ClosedAt,
    88  			pr.MergedAt,
    89  			pr.Merged,
    90  			pr.State,
    91  			pr.Additions,
    92  			pr.Deletions,
    93  			pr.MergedBy).
    94  		WillReturnRows(sqlmock.NewRows([]string{"id"}).AddRow(pr.ID))
    95  	mock.ExpectCommit()
    96  
    97  	// Execute method
    98  	err := cdb.NewPullRequest(pr)
    99  	if err != nil {
   100  		t.Errorf("UserNew unwanted error: %s", err)
   101  	}
   102  
   103  	// Make sure expectations were met for both success and failure
   104  	// conditions
   105  	err = mock.ExpectationsWereMet()
   106  	if err != nil {
   107  		t.Errorf("unfulfilled expectations: %s", err)
   108  	}
   109  }
   110  
   111  func TestUpdatePullRequests(t *testing.T) {
   112  	cdb, mock, close := setupTestDB(t)
   113  	defer close()
   114  
   115  	now := time.Now()
   116  	// Arguments
   117  	id := "https://github.com/decred/github/pull/1" +
   118  		strconv.Itoa(int(now.Unix()))
   119  	pr := &database.PullRequest{
   120  		ID:           id,
   121  		Repo:         "github",
   122  		Organization: "decred",
   123  		URL:          "https://github.com/decred/github/pull/1",
   124  		Number:       1,
   125  		User:         "stakey",
   126  		UpdatedAt:    now.Unix(),
   127  		ClosedAt:     now.Unix(),
   128  		MergedAt:     now.Unix(),
   129  		Merged:       true,
   130  		State:        "MERGED",
   131  		Additions:    100,
   132  		Deletions:    99,
   133  		MergedBy:     "davec",
   134  	}
   135  	// Arguments
   136  	sqlUpdatePullRequests := `UPDATE "pullrequests" ` +
   137  		`SET "repo" = $1, "organization" = $2, "url" = $3, "number" = $4, ` +
   138  		`"author" = $5, "updated_at" = $6, "closed_at" = $7, ` +
   139  		`"merged_at" = $8, "merged" = $9, "state" = $10, "additions" = $11, ` +
   140  		`"deletions" = $12, "merged_by" = $13 ` +
   141  		`WHERE "pullrequests"."id" = $14`
   142  
   143  	// Success Expectations
   144  	mock.ExpectBegin()
   145  	mock.ExpectExec(regexp.QuoteMeta(sqlUpdatePullRequests)).
   146  		WithArgs(
   147  			pr.Repo,
   148  			pr.Organization,
   149  			pr.URL,
   150  			pr.Number,
   151  			pr.User,
   152  			pr.UpdatedAt,
   153  			pr.ClosedAt,
   154  			pr.MergedAt,
   155  			pr.Merged,
   156  			pr.State,
   157  			pr.Additions,
   158  			pr.Deletions,
   159  			pr.MergedBy,
   160  			pr.ID).
   161  		WillReturnResult(sqlmock.NewResult(1, 1))
   162  	mock.ExpectCommit()
   163  
   164  	// Execute method
   165  	err := cdb.UpdatePullRequest(pr)
   166  	if err != nil {
   167  		t.Errorf("UpdatePullRequest unwanted error: %s", err)
   168  	}
   169  
   170  	// Make sure expectations were met
   171  	err = mock.ExpectationsWereMet()
   172  	if err != nil {
   173  		t.Errorf("unfulfilled expectations: %s", err)
   174  	}
   175  }
   176  
   177  func TestNewPullRequestsReview(t *testing.T) {
   178  	cdb, mock, close := setupTestDB(t)
   179  	defer close()
   180  
   181  	now := time.Now()
   182  	// Arguments
   183  	review := &database.PullRequestReview{
   184  		PullRequestURL: "https://github.com/decred/github/pull/1",
   185  		Author:         "stakey",
   186  		State:          "APPROVED",
   187  		SubmittedAt:    now.Unix(),
   188  		Repo:           "github",
   189  		Number:         1,
   190  		ID:             4934324,
   191  	}
   192  
   193  	// Queries
   194  	sqlInsertPullRequests := `INSERT INTO "reviews" ` +
   195  		`("pull_request_url","id","author","state","submitted_at",` +
   196  		`"commit_id","repo","number") ` +
   197  		`VALUES ($1,$2,$3,$4,$5,$6,$7,$8) ` +
   198  		`RETURNING "reviews"."id"`
   199  
   200  	// Success Expectations
   201  	mock.ExpectBegin()
   202  	// Insert user to db
   203  	mock.ExpectQuery(regexp.QuoteMeta(sqlInsertPullRequests)).
   204  		WithArgs(
   205  			review.PullRequestURL,
   206  			review.ID,
   207  			review.Author,
   208  			review.State,
   209  			review.SubmittedAt,
   210  			sqlmock.AnyArg(),
   211  			review.Repo,
   212  			review.Number,
   213  		).
   214  		WillReturnRows(sqlmock.NewRows([]string{"id"}).AddRow(review.ID))
   215  	mock.ExpectCommit()
   216  
   217  	// Execute method
   218  	err := cdb.NewPullRequestReview(review)
   219  	if err != nil {
   220  		t.Errorf("UserNew unwanted error: %s", err)
   221  	}
   222  
   223  	// Make sure expectations were met for both success and failure
   224  	// conditions
   225  	err = mock.ExpectationsWereMet()
   226  	if err != nil {
   227  		t.Errorf("unfulfilled expectations: %s", err)
   228  	}
   229  }
   230  
   231  func TestUpdatePullRequestsReview(t *testing.T) {
   232  	cdb, mock, close := setupTestDB(t)
   233  	defer close()
   234  
   235  	now := time.Now()
   236  	// Arguments
   237  	review := &database.PullRequestReview{
   238  		PullRequestURL: "https://github.com/decred/github/pull/1",
   239  		Author:         "stakey",
   240  		State:          "APPROVED",
   241  		SubmittedAt:    now.Unix(),
   242  		Repo:           "github",
   243  		Number:         1,
   244  		ID:             4934324,
   245  	}
   246  	// Queries
   247  	sqlUpdatePullRequests := `UPDATE "reviews" ` +
   248  		`SET "pull_request_url" = $1, "author" = $2, "state" = $3, ` +
   249  		`"submitted_at" = $4, "commit_id" = $5, "repo" = $6, "number" = $7 ` +
   250  		`WHERE "reviews"."id" = $8`
   251  
   252  	// Success Expectations
   253  	mock.ExpectBegin()
   254  	mock.ExpectExec(regexp.QuoteMeta(sqlUpdatePullRequests)).
   255  		WithArgs(
   256  			review.PullRequestURL,
   257  			review.Author,
   258  			review.State,
   259  			review.SubmittedAt,
   260  			sqlmock.AnyArg(),
   261  			review.Repo,
   262  			review.Number,
   263  			review.ID).
   264  		WillReturnResult(sqlmock.NewResult(1, 1))
   265  	mock.ExpectCommit()
   266  
   267  	// Execute method
   268  	err := cdb.UpdatePullRequestReview(review)
   269  	if err != nil {
   270  		t.Errorf("UpdatePullRequestReview unwanted error: %s", err)
   271  	}
   272  
   273  	// Make sure expectations were met
   274  	err = mock.ExpectationsWereMet()
   275  	if err != nil {
   276  		t.Errorf("unfulfilled expectations: %s", err)
   277  	}
   278  }
   279  
   280  func TestPullRequestByID(t *testing.T) {
   281  	cdb, mock, close := setupTestDB(t)
   282  	defer close()
   283  
   284  	// Arguments
   285  	now := time.Now()
   286  	url := "https://github.com/decred/pr/pull/1"
   287  
   288  	id := url +
   289  		strconv.Itoa(int(now.Unix()))
   290  	idNotFound := url + "123456"
   291  	pr := &database.PullRequest{
   292  		ID:           id,
   293  		Repo:         "github",
   294  		Organization: "decred",
   295  		URL:          url,
   296  		Number:       1,
   297  		User:         "stakey",
   298  		UpdatedAt:    now.Unix(),
   299  		ClosedAt:     now.Unix(),
   300  		MergedAt:     now.Unix(),
   301  		Merged:       true,
   302  		State:        "MERGED",
   303  		Additions:    100,
   304  		Deletions:    99,
   305  		MergedBy:     "davec",
   306  	}
   307  
   308  	// Mock rows data
   309  	rows := sqlmock.NewRows([]string{
   310  		"id",
   311  		"repo",
   312  		"organization",
   313  		"url",
   314  		"number",
   315  		"author",
   316  		"updated_at",
   317  		"closed_at",
   318  		"merged_at",
   319  		"merged",
   320  		"state",
   321  		"additions",
   322  		"deletions",
   323  		"merged_by",
   324  	}).AddRow(
   325  		pr.ID,
   326  		pr.Repo,
   327  		pr.Organization,
   328  		pr.URL,
   329  		pr.Number,
   330  		pr.User,
   331  		pr.UpdatedAt,
   332  		pr.ClosedAt,
   333  		pr.MergedAt,
   334  		pr.Merged,
   335  		pr.State,
   336  		pr.Additions,
   337  		pr.Deletions,
   338  		pr.MergedBy,
   339  	)
   340  
   341  	// Query
   342  	sql := `SELECT * FROM "pullrequests" WHERE "pullrequests"."id" = $1`
   343  
   344  	// Success Expectations
   345  	mock.ExpectQuery(regexp.QuoteMeta(sql)).
   346  		WithArgs(id).
   347  		WillReturnRows(rows)
   348  
   349  	// Execute method
   350  	_, err := cdb.PullRequestByID(id)
   351  	if err != nil {
   352  		t.Errorf("PullRequestByURL unwanted error: %s", err)
   353  	}
   354  
   355  	expectedError := database.ErrNoPullRequestFound
   356  	mock.ExpectQuery(regexp.QuoteMeta(sql)).
   357  		WithArgs(idNotFound).
   358  		WillReturnError(expectedError)
   359  
   360  	foundPr, err := cdb.PullRequestByID(idNotFound)
   361  	if err == nil {
   362  		t.Errorf("expecting error but there was none")
   363  	}
   364  
   365  	if foundPr != nil {
   366  		t.Errorf("expecting nil pr to be returned, but got non-nil pr")
   367  	}
   368  
   369  	// Make sure we got the expected error
   370  	if err != expectedError {
   371  		t.Errorf("expecting error %s but got %s", expectedError, err)
   372  	}
   373  
   374  	// Make sure expectations were met
   375  	err = mock.ExpectationsWereMet()
   376  	if err != nil {
   377  		t.Errorf("unfulfilled expectations: %s", err)
   378  	}
   379  }
   380  
   381  func TestMergedPullRequestsByUserDates(t *testing.T) {
   382  	cdb, mock, close := setupTestDB(t)
   383  	defer close()
   384  
   385  	now := time.Now()
   386  	prURLFirst := "https://github.com/decred/github/pull/1"
   387  	prURLSecond := "https://github.com/decred/github/pull/2"
   388  	prURLThird := "https://github.com/decred/github/pull/3"
   389  
   390  	prFirst := &database.PullRequest{
   391  		Repo:         "github",
   392  		Organization: "decred",
   393  		URL:          prURLFirst,
   394  		Number:       1,
   395  		User:         "stakey_author",
   396  		UpdatedAt:    now.Unix(),
   397  		ClosedAt:     now.Unix(),
   398  		MergedAt:     now.Unix(),
   399  		Merged:       true,
   400  		State:        "MERGED",
   401  		Additions:    11,
   402  		Deletions:    11,
   403  		MergedBy:     "davec",
   404  	}
   405  
   406  	prSecond := &database.PullRequest{
   407  		Repo:         "github",
   408  		Organization: "decred",
   409  		URL:          prURLSecond,
   410  		Number:       2,
   411  		User:         "stakey_author",
   412  		UpdatedAt:    now.Unix(),
   413  		ClosedAt:     now.Unix(),
   414  		MergedAt:     now.Unix(),
   415  		Merged:       true,
   416  		State:        "MERGED",
   417  		Additions:    22,
   418  		Deletions:    22,
   419  		MergedBy:     "davec",
   420  	}
   421  
   422  	prThird := &database.PullRequest{
   423  		Repo:         "github",
   424  		Organization: "decred",
   425  		URL:          prURLThird,
   426  		Number:       3,
   427  		User:         "stakey_author",
   428  		UpdatedAt:    now.Unix(),
   429  		ClosedAt:     now.Unix(),
   430  		MergedAt:     now.Unix(),
   431  		Merged:       true,
   432  		State:        "MERGED",
   433  		Additions:    33,
   434  		Deletions:    33,
   435  		MergedBy:     "davec",
   436  	}
   437  
   438  	// Mock rows data
   439  	rows := sqlmock.NewRows([]string{
   440  		"repo",
   441  		"organization",
   442  		"url",
   443  		"number",
   444  		"author",
   445  		"updated_at",
   446  		"closed_at",
   447  		"merged_at",
   448  		"merged",
   449  		"state",
   450  		"additions",
   451  		"deletions",
   452  		"merged_by",
   453  	}).AddRow(
   454  		prFirst.Repo,
   455  		prFirst.Organization,
   456  		prFirst.URL,
   457  		prFirst.Number,
   458  		prFirst.User,
   459  		prFirst.UpdatedAt,
   460  		prFirst.ClosedAt,
   461  		prFirst.MergedAt,
   462  		prFirst.Merged,
   463  		prFirst.State,
   464  		prFirst.Additions,
   465  		prFirst.Deletions,
   466  		prFirst.MergedBy,
   467  	).AddRow(
   468  		prSecond.Repo,
   469  		prSecond.Organization,
   470  		prSecond.URL,
   471  		prSecond.Number,
   472  		prSecond.User,
   473  		prSecond.UpdatedAt,
   474  		prSecond.ClosedAt,
   475  		prSecond.MergedAt,
   476  		prSecond.Merged,
   477  		prSecond.State,
   478  		prSecond.Additions,
   479  		prSecond.Deletions,
   480  		prSecond.MergedBy,
   481  	).AddRow(
   482  		prThird.Repo,
   483  		prThird.Organization,
   484  		prThird.URL,
   485  		prThird.Number,
   486  		prThird.User,
   487  		prThird.UpdatedAt,
   488  		prThird.ClosedAt,
   489  		prThird.MergedAt,
   490  		prThird.Merged,
   491  		prThird.State,
   492  		prThird.Additions,
   493  		prThird.Deletions,
   494  		prThird.MergedBy,
   495  	)
   496  
   497  	bothRangeStart := now.Add(-2 * time.Hour).Unix()
   498  	bothRangeEnd := now.Add(time.Minute).Unix()
   499  
   500  	// Query
   501  	sql := `
   502  	SELECT * ` +
   503  		`FROM "pullrequests" ` +
   504  		`WHERE (author = $1 AND merged_at BETWEEN $2 AND $3)`
   505  
   506  	// Success Expectations
   507  	mock.ExpectQuery(regexp.QuoteMeta(sql)).
   508  		WithArgs(prFirst.User, bothRangeStart, bothRangeEnd).
   509  		WillReturnRows(rows)
   510  
   511  	// Execute method
   512  	_, err := cdb.MergedPullRequestsByUserDates(prFirst.User, bothRangeStart,
   513  		bothRangeEnd)
   514  	if err != nil {
   515  		t.Errorf("MergedPullRequestsByUserDates unwanted error: %s", err)
   516  	}
   517  	// Make sure expectations were met
   518  	err = mock.ExpectationsWereMet()
   519  	if err != nil {
   520  		t.Errorf("unfulfilled expectations: %s", err)
   521  	}
   522  }
   523  
   524  func TestUpdatedPullRequestsByUserDates(t *testing.T) {
   525  	cdb, mock, close := setupTestDB(t)
   526  	defer close()
   527  
   528  	now := time.Now()
   529  	prURLFirst := "https://github.com/decred/github/pull/1"
   530  	prURLSecond := "https://github.com/decred/github/pull/2"
   531  	prURLThird := "https://github.com/decred/github/pull/3"
   532  
   533  	prFirst := &database.PullRequest{
   534  		Repo:         "github",
   535  		Organization: "decred",
   536  		URL:          prURLFirst,
   537  		Number:       1,
   538  		User:         "stakey_author",
   539  		UpdatedAt:    now.Unix(),
   540  		ClosedAt:     now.Unix(),
   541  		MergedAt:     now.Unix(),
   542  		Merged:       false,
   543  		State:        "UPDATED",
   544  		Additions:    11,
   545  		Deletions:    11,
   546  		MergedBy:     "davec",
   547  	}
   548  
   549  	prSecond := &database.PullRequest{
   550  		Repo:         "github",
   551  		Organization: "decred",
   552  		URL:          prURLSecond,
   553  		Number:       2,
   554  		User:         "stakey_author",
   555  		UpdatedAt:    now.Unix(),
   556  		ClosedAt:     now.Unix(),
   557  		MergedAt:     now.Unix(),
   558  		Merged:       false,
   559  		State:        "UPDATED",
   560  		Additions:    22,
   561  		Deletions:    22,
   562  		MergedBy:     "davec",
   563  	}
   564  
   565  	prThird := &database.PullRequest{
   566  		Repo:         "github",
   567  		Organization: "decred",
   568  		URL:          prURLThird,
   569  		Number:       3,
   570  		User:         "stakey_author",
   571  		UpdatedAt:    now.Unix(),
   572  		ClosedAt:     now.Unix(),
   573  		MergedAt:     now.Unix(),
   574  		Merged:       false,
   575  		State:        "UPDATED",
   576  		Additions:    33,
   577  		Deletions:    33,
   578  		MergedBy:     "davec",
   579  	}
   580  
   581  	// Mock rows data
   582  	rows := sqlmock.NewRows([]string{
   583  		"repo",
   584  		"organization",
   585  		"url",
   586  		"number",
   587  		"author",
   588  		"updated_at",
   589  		"closed_at",
   590  		"merged_at",
   591  		"merged",
   592  		"state",
   593  		"additions",
   594  		"deletions",
   595  		"merged_by",
   596  	}).AddRow(
   597  		prFirst.Repo,
   598  		prFirst.Organization,
   599  		prFirst.URL,
   600  		prFirst.Number,
   601  		prFirst.User,
   602  		prFirst.UpdatedAt,
   603  		prFirst.ClosedAt,
   604  		prFirst.MergedAt,
   605  		prFirst.Merged,
   606  		prFirst.State,
   607  		prFirst.Additions,
   608  		prFirst.Deletions,
   609  		prFirst.MergedBy,
   610  	).AddRow(
   611  		prSecond.Repo,
   612  		prSecond.Organization,
   613  		prSecond.URL,
   614  		prSecond.Number,
   615  		prSecond.User,
   616  		prSecond.UpdatedAt,
   617  		prSecond.ClosedAt,
   618  		prSecond.MergedAt,
   619  		prSecond.Merged,
   620  		prSecond.State,
   621  		prSecond.Additions,
   622  		prSecond.Deletions,
   623  		prSecond.MergedBy,
   624  	).AddRow(
   625  		prThird.Repo,
   626  		prThird.Organization,
   627  		prThird.URL,
   628  		prThird.Number,
   629  		prThird.User,
   630  		prThird.UpdatedAt,
   631  		prThird.ClosedAt,
   632  		prThird.MergedAt,
   633  		prThird.Merged,
   634  		prThird.State,
   635  		prThird.Additions,
   636  		prThird.Deletions,
   637  		prThird.MergedBy,
   638  	)
   639  
   640  	bothRangeStart := now.Add(-2 * time.Hour).Unix()
   641  	bothRangeEnd := now.Add(time.Minute).Unix()
   642  
   643  	// Query
   644  	sql := `
   645  	SELECT * FROM pullrequests 
   646  	WHERE author = $1 AND updated_at IN 
   647  	(SELECT 
   648  		MAX(updated_at) 
   649  		FROM pullrequests 
   650  		WHERE updated_at BETWEEN $2 AND $3 
   651  		GROUP BY url
   652  	)
   653  	`
   654  
   655  	// Success Expectations
   656  	mock.ExpectQuery(regexp.QuoteMeta(sql)).
   657  		WithArgs(prFirst.User, bothRangeStart, bothRangeEnd).
   658  		WillReturnRows(rows)
   659  
   660  	// Execute method
   661  	_, err := cdb.UpdatedPullRequestsByUserDates(prFirst.User, bothRangeStart,
   662  		bothRangeEnd)
   663  	if err != nil {
   664  		t.Errorf("UpdatedPullRequestsByUserDates unwanted error: %s", err)
   665  	}
   666  	// Make sure expectations were met
   667  	err = mock.ExpectationsWereMet()
   668  	if err != nil {
   669  		t.Errorf("unfulfilled expectations: %s", err)
   670  	}
   671  }
   672  func TestPullRequestsByURL(t *testing.T) {
   673  	cdb, mock, close := setupTestDB(t)
   674  	defer close()
   675  
   676  	now := time.Now()
   677  	prURLFirst := "https://github.com/decred/github/pull/1"
   678  	prURLSecond := "https://github.com/decred/github/pull/2"
   679  	prURLThird := "https://github.com/decred/github/pull/3"
   680  
   681  	prFirst := &database.PullRequest{
   682  		Repo:         "github",
   683  		Organization: "decred",
   684  		URL:          prURLFirst,
   685  		Number:       1,
   686  		User:         "stakey_author",
   687  		UpdatedAt:    now.Unix(),
   688  		ClosedAt:     now.Unix(),
   689  		MergedAt:     now.Unix(),
   690  		Merged:       true,
   691  		State:        "MERGED",
   692  		Additions:    11,
   693  		Deletions:    11,
   694  		MergedBy:     "davec",
   695  	}
   696  
   697  	prSecond := &database.PullRequest{
   698  		Repo:         "github",
   699  		Organization: "decred",
   700  		URL:          prURLSecond,
   701  		Number:       2,
   702  		User:         "stakey_author",
   703  		UpdatedAt:    now.Unix(),
   704  		ClosedAt:     now.Unix(),
   705  		MergedAt:     now.Unix(),
   706  		Merged:       true,
   707  		State:        "MERGED",
   708  		Additions:    22,
   709  		Deletions:    22,
   710  		MergedBy:     "davec",
   711  	}
   712  
   713  	prThird := &database.PullRequest{
   714  		Repo:         "github",
   715  		Organization: "decred",
   716  		URL:          prURLThird,
   717  		Number:       3,
   718  		User:         "stakey_author",
   719  		UpdatedAt:    now.Unix(),
   720  		ClosedAt:     now.Unix(),
   721  		MergedAt:     now.Unix(),
   722  		Merged:       true,
   723  		State:        "MERGED",
   724  		Additions:    33,
   725  		Deletions:    33,
   726  		MergedBy:     "davec",
   727  	}
   728  
   729  	// Mock rows data
   730  	rows := sqlmock.NewRows([]string{
   731  		"repo",
   732  		"organization",
   733  		"url",
   734  		"number",
   735  		"author",
   736  		"updated_at",
   737  		"closed_at",
   738  		"merged_at",
   739  		"merged",
   740  		"state",
   741  		"additions",
   742  		"deletions",
   743  		"merged_by",
   744  	}).AddRow(
   745  		prFirst.Repo,
   746  		prFirst.Organization,
   747  		prFirst.URL,
   748  		prFirst.Number,
   749  		prFirst.User,
   750  		prFirst.UpdatedAt,
   751  		prFirst.ClosedAt,
   752  		prFirst.MergedAt,
   753  		prFirst.Merged,
   754  		prFirst.State,
   755  		prFirst.Additions,
   756  		prFirst.Deletions,
   757  		prFirst.MergedBy,
   758  	).AddRow(
   759  		prSecond.Repo,
   760  		prSecond.Organization,
   761  		prSecond.URL,
   762  		prSecond.Number,
   763  		prSecond.User,
   764  		prSecond.UpdatedAt,
   765  		prSecond.ClosedAt,
   766  		prSecond.MergedAt,
   767  		prSecond.Merged,
   768  		prSecond.State,
   769  		prSecond.Additions,
   770  		prSecond.Deletions,
   771  		prSecond.MergedBy,
   772  	).AddRow(
   773  		prThird.Repo,
   774  		prThird.Organization,
   775  		prThird.URL,
   776  		prThird.Number,
   777  		prThird.User,
   778  		prThird.UpdatedAt,
   779  		prThird.ClosedAt,
   780  		prThird.MergedAt,
   781  		prThird.Merged,
   782  		prThird.State,
   783  		prThird.Additions,
   784  		prThird.Deletions,
   785  		prThird.MergedBy,
   786  	)
   787  
   788  	// Query
   789  	sql := `
   790  	SELECT * ` +
   791  		`FROM "pullrequests" ` +
   792  		`WHERE (url = $1)`
   793  
   794  	// Success Expectations
   795  	mock.ExpectQuery(regexp.QuoteMeta(sql)).
   796  		WithArgs(prFirst.URL).
   797  		WillReturnRows(rows)
   798  
   799  	// Execute method
   800  	_, err := cdb.PullRequestsByURL(prFirst.URL)
   801  	if err != nil {
   802  		t.Errorf("PullRequestsByURL unwanted error: %s", err)
   803  	}
   804  	// Make sure expectations were met
   805  	err = mock.ExpectationsWereMet()
   806  	if err != nil {
   807  		t.Errorf("unfulfilled expectations: %s", err)
   808  	}
   809  }
   810  
   811  func TestReviewByID(t *testing.T) {
   812  	cdb, mock, close := setupTestDB(t)
   813  	defer close()
   814  
   815  	// Arguments
   816  	now := time.Now()
   817  	authorStakey := "stakey"
   818  
   819  	prURLFirst := "https://github.com/decred/github/pull/1"
   820  
   821  	reviewFirst := &database.PullRequestReview{
   822  		ID:             434234234,
   823  		Repo:           "github",
   824  		PullRequestURL: prURLFirst,
   825  		Number:         1,
   826  		Author:         authorStakey,
   827  		SubmittedAt:    now.Unix(),
   828  		State:          "APPROVED",
   829  		Additions:      11,
   830  		Deletions:      11,
   831  		CommitID:       "abcd1234",
   832  	}
   833  
   834  	rows := sqlmock.NewRows([]string{
   835  		"pull_request_url",
   836  		"id",
   837  		"author",
   838  		"state",
   839  		"submitted_at",
   840  		"commit_id",
   841  		"repo",
   842  		"number",
   843  	}).AddRow(
   844  		reviewFirst.PullRequestURL,
   845  		reviewFirst.ID,
   846  		reviewFirst.Author,
   847  		reviewFirst.State,
   848  		reviewFirst.SubmittedAt,
   849  		reviewFirst.CommitID,
   850  		reviewFirst.Repo,
   851  		reviewFirst.Number,
   852  	)
   853  
   854  	idNotFound := int64(123456)
   855  	// Query
   856  	sql := `SELECT * FROM "reviews" WHERE "reviews"."id" = $1`
   857  
   858  	// Success Expectations
   859  	mock.ExpectQuery(regexp.QuoteMeta(sql)).
   860  		WithArgs(reviewFirst.ID).
   861  		WillReturnRows(rows)
   862  
   863  	// Execute method
   864  	_, err := cdb.ReviewByID(reviewFirst.ID)
   865  	if err != nil {
   866  		t.Errorf("PullRequestByURL unwanted error: %s", err)
   867  	}
   868  
   869  	expectedError := database.ErrNoPullRequestReviewFound
   870  	mock.ExpectQuery(regexp.QuoteMeta(sql)).
   871  		WithArgs(idNotFound).
   872  		WillReturnError(expectedError)
   873  
   874  	foundPr, err := cdb.ReviewByID(idNotFound)
   875  	if err == nil {
   876  		t.Errorf("expecting error but there was none")
   877  	}
   878  
   879  	if foundPr != nil {
   880  		t.Errorf("expecting nil pr to be returned, but got non-nil pr")
   881  	}
   882  
   883  	// Make sure we got the expected error
   884  	if err != expectedError {
   885  		t.Errorf("expecting error %s but got %s", expectedError, err)
   886  	}
   887  
   888  	// Make sure expectations were met
   889  	err = mock.ExpectationsWereMet()
   890  	if err != nil {
   891  		t.Errorf("unfulfilled expectations: %s", err)
   892  	}
   893  }
   894  
   895  func TestReviewsByUserDates(t *testing.T) {
   896  	cdb, mock, close := setupTestDB(t)
   897  	defer close()
   898  
   899  	now := time.Now()
   900  	authorStakey := "stakey"
   901  
   902  	prURLFirst := "https://github.com/decred/github/pull/1"
   903  	prURLSecond := "https://github.com/decred/github/pull/2"
   904  
   905  	reviewFirst := &database.PullRequestReview{
   906  		ID:             434234234,
   907  		Repo:           "github",
   908  		PullRequestURL: prURLFirst,
   909  		Number:         1,
   910  		Author:         authorStakey,
   911  		SubmittedAt:    now.Unix(),
   912  		State:          "APPROVED",
   913  		Additions:      11,
   914  		Deletions:      11,
   915  		CommitID:       "abcd1234",
   916  	}
   917  
   918  	reviewSecond := &database.PullRequestReview{
   919  		ID:             434234235,
   920  		Repo:           "github",
   921  		PullRequestURL: prURLSecond,
   922  		Number:         2,
   923  		Author:         authorStakey,
   924  		SubmittedAt:    now.Add(-1 * time.Hour).Unix(),
   925  		State:          "APPROVED",
   926  		CommitID:       "abcd1236",
   927  	}
   928  
   929  	rows := sqlmock.NewRows([]string{
   930  		"pull_request_url",
   931  		"id",
   932  		"author",
   933  		"state",
   934  		"submitted_at",
   935  		"commit_id",
   936  		"repo",
   937  		"number",
   938  	}).AddRow(
   939  		reviewFirst.PullRequestURL,
   940  		reviewFirst.ID,
   941  		reviewFirst.Author,
   942  		reviewFirst.State,
   943  		reviewFirst.SubmittedAt,
   944  		reviewFirst.CommitID,
   945  		reviewFirst.Repo,
   946  		reviewFirst.Number,
   947  	).AddRow(
   948  		reviewSecond.PullRequestURL,
   949  		reviewSecond.ID,
   950  		reviewSecond.Author,
   951  		reviewSecond.State,
   952  		reviewSecond.SubmittedAt,
   953  		reviewSecond.CommitID,
   954  		reviewSecond.Repo,
   955  		reviewSecond.Number,
   956  	)
   957  
   958  	bothRangeStart := now.Add(-2 * time.Hour).Unix()
   959  	bothRangeEnd := now.Add(time.Minute).Unix()
   960  
   961  	// Query
   962  	sql := `
   963      SELECT 
   964  	  reviews.pull_request_url,
   965  	  reviews.id,
   966  	  reviews.author,
   967  	  reviews.state,
   968  	  reviews.submitted_at,
   969  	  reviews.commit_id,
   970  	  reviews.repo,
   971  	  reviews.number,
   972  	  pullrequests.additions,
   973  	  pullrequests.deletions
   974      FROM reviews
   975      INNER JOIN pullrequests
   976  	  ON pullrequests.url = reviews.pull_request_url
   977      WHERE reviews.author = $1 AND reviews.state = $2 AND 
   978  	  reviews.submitted_at BETWEEN $3 AND $4`
   979  
   980  	// Success Expectations
   981  	mock.ExpectQuery(regexp.QuoteMeta(sql)).
   982  		WithArgs(reviewFirst.Author, "APPROVED", bothRangeStart, bothRangeEnd).
   983  		WillReturnRows(rows)
   984  
   985  	// Execute method
   986  	_, err := cdb.ReviewsByUserDates(reviewFirst.Author, bothRangeStart,
   987  		bothRangeEnd)
   988  	if err != nil {
   989  		t.Errorf("ReviewsByUserDate unwanted error: %s", err)
   990  	}
   991  
   992  	// Make sure expectations were met
   993  	err = mock.ExpectationsWereMet()
   994  	if err != nil {
   995  		t.Errorf("unfulfilled expectations: %s", err)
   996  	}
   997  }
   998  
   999  func TestNewCommits(t *testing.T) {
  1000  	cdb, mock, close := setupTestDB(t)
  1001  	defer close()
  1002  
  1003  	now := time.Now()
  1004  	// Arguments
  1005  	sha := "40deb80dea8c560dfc851a6c0fce6f29f8ecb57a"
  1006  	url := "https://api.github.com/repos/decred/politeia/commits/40deb80dea8c560dfc851a6c0fce6f29f8ecb57a"
  1007  	commit := &database.Commit{
  1008  		SHA:          sha,
  1009  		URL:          url,
  1010  		Organization: "decred",
  1011  		Repo:         "politeia",
  1012  		Author:       "stakey",
  1013  		Committer:    "stakey",
  1014  		Date:         now.Unix(),
  1015  		Message:      "This is a sweet commit!",
  1016  		ParentSHA:    "8575154a09049b042634333ad39c3a710c309105",
  1017  		ParentURL:    "https://api.github.com/repos/decred/politeia/commits/8575154a09049b042634333ad39c3a710c309105",
  1018  		Additions:    100,
  1019  		Deletions:    99,
  1020  	}
  1021  
  1022  	// Queries
  1023  	sqlInsertPullRequests := `INSERT INTO "commits" ` +
  1024  		`("sha","repo","organization","date","author","committer","message",` +
  1025  		`"url","parent_sha","parent_url","additions","deletions") ` +
  1026  		`VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12) ` +
  1027  		`RETURNING "commits"."sha"`
  1028  
  1029  	// Success Expectations
  1030  	mock.ExpectBegin()
  1031  	// Insert user to db
  1032  	mock.ExpectQuery(regexp.QuoteMeta(sqlInsertPullRequests)).
  1033  		WithArgs(
  1034  			commit.SHA,
  1035  			commit.Repo,
  1036  			commit.Organization,
  1037  			commit.Date,
  1038  			commit.Author,
  1039  			commit.Committer,
  1040  			commit.Message,
  1041  			commit.URL,
  1042  			commit.ParentSHA,
  1043  			commit.ParentURL,
  1044  			commit.Additions,
  1045  			commit.Deletions,
  1046  		).
  1047  		WillReturnRows(sqlmock.NewRows([]string{"sha"}).AddRow(commit.SHA))
  1048  	mock.ExpectCommit()
  1049  
  1050  	// Execute method
  1051  	err := cdb.NewCommit(commit)
  1052  	if err != nil {
  1053  		t.Errorf("UserNew unwanted error: %s", err)
  1054  	}
  1055  
  1056  	// Make sure expectations were met for both success and failure
  1057  	// conditions
  1058  	err = mock.ExpectationsWereMet()
  1059  	if err != nil {
  1060  		t.Errorf("unfulfilled expectations: %s", err)
  1061  	}
  1062  }
  1063  
  1064  func TestCommitsByUserDates(t *testing.T) {
  1065  	cdb, mock, close := setupTestDB(t)
  1066  	defer close()
  1067  
  1068  	now := time.Now()
  1069  
  1070  	commitFirst := &database.Commit{
  1071  		SHA:          "5a673974e617fc2a5bc67878d8161c103583d968",
  1072  		URL:          "https://api.github.com/repos/decred/politeia/commits/5a673974e617fc2a5bc67878d8161c103583d968",
  1073  		Organization: "decred",
  1074  		Repo:         "politeia",
  1075  		Author:       "stakey",
  1076  		Committer:    "stakey",
  1077  		Date:         now.Unix(),
  1078  		Message:      "This is a sweet commit! Again",
  1079  		ParentSHA:    "8575154a09049b042634333ad39c3a710c309105",
  1080  		ParentURL:    "https://api.github.com/repos/decred/politeia/commits/8575154a09049b042634333ad39c3a710c309105",
  1081  		Additions:    100,
  1082  		Deletions:    99,
  1083  	}
  1084  
  1085  	commitSecond := &database.Commit{
  1086  		SHA:          "8575154a09049b042634333ad39c3a710c309105",
  1087  		URL:          "https://api.github.com/repos/decred/politeia/commits/8575154a09049b042634333ad39c3a710c309105",
  1088  		Organization: "decred",
  1089  		Repo:         "politeia",
  1090  		Author:       "stakey",
  1091  		Committer:    "stakey",
  1092  		Date:         now.Unix(),
  1093  		Message:      "This is a sweet commit!",
  1094  		ParentSHA:    "883f75a641b969ce0e7313219efcc0c94f30fd01",
  1095  		ParentURL:    "https://api.github.com/repos/decred/politeia/commits/883f75a641b969ce0e7313219efcc0c94f30fd01",
  1096  		Additions:    100,
  1097  		Deletions:    99,
  1098  	}
  1099  
  1100  	rows := sqlmock.NewRows([]string{
  1101  		"sha",
  1102  		"repo",
  1103  		"organization",
  1104  		"date",
  1105  		"author",
  1106  		"committer",
  1107  		"message",
  1108  		"url",
  1109  		"parent_sha",
  1110  		"parent_url",
  1111  		"additions",
  1112  		"deletions",
  1113  	}).AddRow(
  1114  		commitFirst.SHA,
  1115  		commitFirst.Repo,
  1116  		commitFirst.Organization,
  1117  		commitFirst.Date,
  1118  		commitFirst.Author,
  1119  		commitFirst.Committer,
  1120  		commitFirst.Message,
  1121  		commitFirst.URL,
  1122  		commitFirst.ParentSHA,
  1123  		commitFirst.ParentURL,
  1124  		commitFirst.Additions,
  1125  		commitFirst.Deletions,
  1126  	).AddRow(
  1127  		commitSecond.SHA,
  1128  		commitSecond.Repo,
  1129  		commitSecond.Organization,
  1130  		commitSecond.Date,
  1131  		commitSecond.Author,
  1132  		commitSecond.Committer,
  1133  		commitSecond.Message,
  1134  		commitSecond.URL,
  1135  		commitSecond.ParentSHA,
  1136  		commitSecond.ParentURL,
  1137  		commitSecond.Additions,
  1138  		commitSecond.Deletions,
  1139  	)
  1140  
  1141  	bothRangeStart := now.Add(-2 * time.Hour).Unix()
  1142  	bothRangeEnd := now.Add(time.Minute).Unix()
  1143  
  1144  	// Query
  1145  	sql := `
  1146      SELECT *
  1147      FROM "commits"
  1148      WHERE (author = $1 AND date BETWEEN $2 AND $3)`
  1149  
  1150  	// Success Expectations
  1151  	mock.ExpectQuery(regexp.QuoteMeta(sql)).
  1152  		WithArgs(commitFirst.Author, bothRangeStart, bothRangeEnd).
  1153  		WillReturnRows(rows)
  1154  
  1155  	// Execute method
  1156  	_, err := cdb.CommitsByUserDates(commitFirst.Author, bothRangeStart,
  1157  		bothRangeEnd)
  1158  	if err != nil {
  1159  		t.Errorf("ReviewsByUserDate unwanted error: %s", err)
  1160  	}
  1161  
  1162  	// Make sure expectations were met
  1163  	err = mock.ExpectationsWereMet()
  1164  	if err != nil {
  1165  		t.Errorf("unfulfilled expectations: %s", err)
  1166  	}
  1167  }
  1168  
  1169  func TestCommitBySHA(t *testing.T) {
  1170  	cdb, mock, close := setupTestDB(t)
  1171  	defer close()
  1172  
  1173  	// Arguments
  1174  	now := time.Now()
  1175  	commitFirst := &database.Commit{
  1176  		SHA:          "5a673974e617fc2a5bc67878d8161c103583d968",
  1177  		URL:          "https://api.github.com/repos/decred/politeia/commits/5a673974e617fc2a5bc67878d8161c103583d968",
  1178  		Organization: "decred",
  1179  		Repo:         "politeia",
  1180  		Author:       "stakey",
  1181  		Committer:    "stakey",
  1182  		Date:         now.Unix(),
  1183  		Message:      "This is a sweet commit! Again",
  1184  		ParentSHA:    "8575154a09049b042634333ad39c3a710c309105",
  1185  		ParentURL:    "https://api.github.com/repos/decred/politeia/commits/8575154a09049b042634333ad39c3a710c309105",
  1186  		Additions:    100,
  1187  		Deletions:    99,
  1188  	}
  1189  
  1190  	rows := sqlmock.NewRows([]string{
  1191  		"sha",
  1192  		"repo",
  1193  		"organization",
  1194  		"date",
  1195  		"author",
  1196  		"committer",
  1197  		"message",
  1198  		"url",
  1199  		"parent_sha",
  1200  		"parent_url",
  1201  		"additions",
  1202  		"deletions",
  1203  	}).AddRow(
  1204  		commitFirst.SHA,
  1205  		commitFirst.Repo,
  1206  		commitFirst.Organization,
  1207  		commitFirst.Date,
  1208  		commitFirst.Author,
  1209  		commitFirst.Committer,
  1210  		commitFirst.Message,
  1211  		commitFirst.URL,
  1212  		commitFirst.ParentSHA,
  1213  		commitFirst.ParentURL,
  1214  		commitFirst.Additions,
  1215  		commitFirst.Deletions,
  1216  	)
  1217  
  1218  	shaNotFound := "8575154a09049b042634333ad39c3a710c309105"
  1219  
  1220  	// Query
  1221  	sql := `SELECT * FROM "commits" WHERE "commits"."sha" = $1`
  1222  
  1223  	// Success Expectations
  1224  	mock.ExpectQuery(regexp.QuoteMeta(sql)).
  1225  		WithArgs(commitFirst.SHA).
  1226  		WillReturnRows(rows)
  1227  
  1228  	// Execute method
  1229  	_, err := cdb.CommitBySHA(commitFirst.SHA)
  1230  	if err != nil {
  1231  		t.Errorf("PullRequestByURL unwanted error: %s", err)
  1232  	}
  1233  
  1234  	expectedError := database.ErrNoCommitFound
  1235  	mock.ExpectQuery(regexp.QuoteMeta(sql)).
  1236  		WithArgs(shaNotFound).
  1237  		WillReturnError(expectedError)
  1238  
  1239  	foundPr, err := cdb.CommitBySHA(shaNotFound)
  1240  	if err == nil {
  1241  		t.Errorf("expecting error but there was none")
  1242  	}
  1243  
  1244  	if foundPr != nil {
  1245  		t.Errorf("expecting nil pr to be returned, but got non-nil pr")
  1246  	}
  1247  
  1248  	// Make sure we got the expected error
  1249  	if err != expectedError {
  1250  		t.Errorf("expecting error %s but got %s", expectedError, err)
  1251  	}
  1252  
  1253  	// Make sure expectations were met
  1254  	err = mock.ExpectationsWereMet()
  1255  	if err != nil {
  1256  		t.Errorf("unfulfilled expectations: %s", err)
  1257  	}
  1258  }