github.com/google/go-github/v66@v66.0.0/github/actions_workflow_runs_test.go (about)

     1  // Copyright 2020 The go-github AUTHORS. All rights reserved.
     2  //
     3  // Use of this source code is governed by a BSD-style
     4  // license that can be found in the LICENSE file.
     5  
     6  package github
     7  
     8  import (
     9  	"context"
    10  	"encoding/json"
    11  	"fmt"
    12  	"net/http"
    13  	"net/url"
    14  	"testing"
    15  	"time"
    16  
    17  	"github.com/google/go-cmp/cmp"
    18  )
    19  
    20  func TestActionsService_ListWorkflowRunsByID(t *testing.T) {
    21  	t.Parallel()
    22  	client, mux, _ := setup(t)
    23  
    24  	mux.HandleFunc("/repos/o/r/actions/workflows/29679449/runs", func(w http.ResponseWriter, r *http.Request) {
    25  		testMethod(t, r, "GET")
    26  		testFormValues(t, r, values{"per_page": "2", "page": "2"})
    27  		fmt.Fprint(w, `{"total_count":4,"workflow_runs":[{"id":399444496,"run_number":296,"created_at":"2019-01-02T15:04:05Z","updated_at":"2020-01-02T15:04:05Z"},{"id":399444497,"run_number":296,"created_at":"2019-01-02T15:04:05Z","updated_at":"2020-01-02T15:04:05Z"}]}`)
    28  	})
    29  
    30  	opts := &ListWorkflowRunsOptions{ListOptions: ListOptions{Page: 2, PerPage: 2}}
    31  	ctx := context.Background()
    32  	runs, _, err := client.Actions.ListWorkflowRunsByID(ctx, "o", "r", 29679449, opts)
    33  	if err != nil {
    34  		t.Errorf("Actions.ListWorkFlowRunsByID returned error: %v", err)
    35  	}
    36  
    37  	want := &WorkflowRuns{
    38  		TotalCount: Int(4),
    39  		WorkflowRuns: []*WorkflowRun{
    40  			{ID: Int64(399444496), RunNumber: Int(296), CreatedAt: &Timestamp{time.Date(2019, time.January, 02, 15, 04, 05, 0, time.UTC)}, UpdatedAt: &Timestamp{time.Date(2020, time.January, 02, 15, 04, 05, 0, time.UTC)}},
    41  			{ID: Int64(399444497), RunNumber: Int(296), CreatedAt: &Timestamp{time.Date(2019, time.January, 02, 15, 04, 05, 0, time.UTC)}, UpdatedAt: &Timestamp{time.Date(2020, time.January, 02, 15, 04, 05, 0, time.UTC)}},
    42  		},
    43  	}
    44  	if !cmp.Equal(runs, want) {
    45  		t.Errorf("Actions.ListWorkflowRunsByID returned %+v, want %+v", runs, want)
    46  	}
    47  
    48  	const methodName = "ListWorkflowRunsByID"
    49  	testBadOptions(t, methodName, func() (err error) {
    50  		_, _, err = client.Actions.ListWorkflowRunsByID(ctx, "\n", "\n", 29679449, opts)
    51  		return err
    52  	})
    53  
    54  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
    55  		got, resp, err := client.Actions.ListWorkflowRunsByID(ctx, "o", "r", 29679449, opts)
    56  		if got != nil {
    57  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
    58  		}
    59  		return resp, err
    60  	})
    61  }
    62  
    63  func TestActionsService_ListWorkflowRunsFileName(t *testing.T) {
    64  	t.Parallel()
    65  	client, mux, _ := setup(t)
    66  
    67  	mux.HandleFunc("/repos/o/r/actions/workflows/29679449/runs", func(w http.ResponseWriter, r *http.Request) {
    68  		testMethod(t, r, "GET")
    69  		testFormValues(t, r, values{"per_page": "2", "page": "2"})
    70  		fmt.Fprint(w, `{"total_count":4,"workflow_runs":[{"id":399444496,"run_number":296,"created_at":"2019-01-02T15:04:05Z","updated_at":"2020-01-02T15:04:05Z"},{"id":399444497,"run_number":296,"created_at":"2019-01-02T15:04:05Z","updated_at":"2020-01-02T15:04:05Z"}]}`)
    71  	})
    72  
    73  	opts := &ListWorkflowRunsOptions{ListOptions: ListOptions{Page: 2, PerPage: 2}}
    74  	ctx := context.Background()
    75  	runs, _, err := client.Actions.ListWorkflowRunsByFileName(ctx, "o", "r", "29679449", opts)
    76  	if err != nil {
    77  		t.Errorf("Actions.ListWorkFlowRunsByFileName returned error: %v", err)
    78  	}
    79  
    80  	want := &WorkflowRuns{
    81  		TotalCount: Int(4),
    82  		WorkflowRuns: []*WorkflowRun{
    83  			{ID: Int64(399444496), RunNumber: Int(296), CreatedAt: &Timestamp{time.Date(2019, time.January, 02, 15, 04, 05, 0, time.UTC)}, UpdatedAt: &Timestamp{time.Date(2020, time.January, 02, 15, 04, 05, 0, time.UTC)}},
    84  			{ID: Int64(399444497), RunNumber: Int(296), CreatedAt: &Timestamp{time.Date(2019, time.January, 02, 15, 04, 05, 0, time.UTC)}, UpdatedAt: &Timestamp{time.Date(2020, time.January, 02, 15, 04, 05, 0, time.UTC)}},
    85  		},
    86  	}
    87  	if !cmp.Equal(runs, want) {
    88  		t.Errorf("Actions.ListWorkflowRunsByFileName returned %+v, want %+v", runs, want)
    89  	}
    90  
    91  	const methodName = "ListWorkflowRunsByFileName"
    92  	testBadOptions(t, methodName, func() (err error) {
    93  		_, _, err = client.Actions.ListWorkflowRunsByFileName(ctx, "\n", "\n", "29679449", opts)
    94  		return err
    95  	})
    96  
    97  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
    98  		got, resp, err := client.Actions.ListWorkflowRunsByFileName(ctx, "o", "r", "29679449", opts)
    99  		if got != nil {
   100  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   101  		}
   102  		return resp, err
   103  	})
   104  }
   105  
   106  func TestActionsService_GetWorkflowRunByID(t *testing.T) {
   107  	t.Parallel()
   108  	client, mux, _ := setup(t)
   109  
   110  	mux.HandleFunc("/repos/o/r/actions/runs/29679449", func(w http.ResponseWriter, r *http.Request) {
   111  		testMethod(t, r, "GET")
   112  		fmt.Fprint(w, `{"id":399444496,"run_number":296,"created_at":"2019-01-02T15:04:05Z","updated_at":"2020-01-02T15:04:05Z"}}`)
   113  	})
   114  
   115  	ctx := context.Background()
   116  	runs, _, err := client.Actions.GetWorkflowRunByID(ctx, "o", "r", 29679449)
   117  	if err != nil {
   118  		t.Errorf("Actions.GetWorkflowRunByID returned error: %v", err)
   119  	}
   120  
   121  	want := &WorkflowRun{
   122  		ID:        Int64(399444496),
   123  		RunNumber: Int(296),
   124  		CreatedAt: &Timestamp{time.Date(2019, time.January, 02, 15, 04, 05, 0, time.UTC)},
   125  		UpdatedAt: &Timestamp{time.Date(2020, time.January, 02, 15, 04, 05, 0, time.UTC)},
   126  	}
   127  
   128  	if !cmp.Equal(runs, want) {
   129  		t.Errorf("Actions.GetWorkflowRunByID returned %+v, want %+v", runs, want)
   130  	}
   131  
   132  	const methodName = "GetWorkflowRunByID"
   133  	testBadOptions(t, methodName, func() (err error) {
   134  		_, _, err = client.Actions.GetWorkflowRunByID(ctx, "\n", "\n", 29679449)
   135  		return err
   136  	})
   137  
   138  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   139  		got, resp, err := client.Actions.GetWorkflowRunByID(ctx, "o", "r", 29679449)
   140  		if got != nil {
   141  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   142  		}
   143  		return resp, err
   144  	})
   145  }
   146  
   147  func TestActionsService_GetWorkflowRunAttempt(t *testing.T) {
   148  	t.Parallel()
   149  	client, mux, _ := setup(t)
   150  
   151  	mux.HandleFunc("/repos/o/r/actions/runs/29679449/attempts/3", func(w http.ResponseWriter, r *http.Request) {
   152  		testMethod(t, r, "GET")
   153  		testFormValues(t, r, values{"exclude_pull_requests": "true"})
   154  		fmt.Fprint(w, `{"id":399444496,"run_number":296,"run_attempt":3,"created_at":"2019-01-02T15:04:05Z","updated_at":"2020-01-02T15:04:05Z"}}`)
   155  	})
   156  
   157  	opts := &WorkflowRunAttemptOptions{ExcludePullRequests: Bool(true)}
   158  	ctx := context.Background()
   159  	runs, _, err := client.Actions.GetWorkflowRunAttempt(ctx, "o", "r", 29679449, 3, opts)
   160  	if err != nil {
   161  		t.Errorf("Actions.GetWorkflowRunAttempt returned error: %v", err)
   162  	}
   163  
   164  	want := &WorkflowRun{
   165  		ID:         Int64(399444496),
   166  		RunNumber:  Int(296),
   167  		RunAttempt: Int(3),
   168  		CreatedAt:  &Timestamp{time.Date(2019, time.January, 02, 15, 04, 05, 0, time.UTC)},
   169  		UpdatedAt:  &Timestamp{time.Date(2020, time.January, 02, 15, 04, 05, 0, time.UTC)},
   170  	}
   171  
   172  	if !cmp.Equal(runs, want) {
   173  		t.Errorf("Actions.GetWorkflowRunAttempt returned %+v, want %+v", runs, want)
   174  	}
   175  
   176  	const methodName = "GetWorkflowRunAttempt"
   177  	testBadOptions(t, methodName, func() (err error) {
   178  		_, _, err = client.Actions.GetWorkflowRunAttempt(ctx, "\n", "\n", 29679449, 3, opts)
   179  		return err
   180  	})
   181  
   182  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   183  		got, resp, err := client.Actions.GetWorkflowRunAttempt(ctx, "o", "r", 29679449, 3, opts)
   184  		if got != nil {
   185  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   186  		}
   187  		return resp, err
   188  	})
   189  }
   190  
   191  func TestActionsService_GetWorkflowRunAttemptLogs(t *testing.T) {
   192  	t.Parallel()
   193  	client, mux, _ := setup(t)
   194  
   195  	mux.HandleFunc("/repos/o/r/actions/runs/399444496/attempts/2/logs", func(w http.ResponseWriter, r *http.Request) {
   196  		testMethod(t, r, "GET")
   197  		http.Redirect(w, r, "http://github.com/a", http.StatusFound)
   198  	})
   199  
   200  	ctx := context.Background()
   201  	url, resp, err := client.Actions.GetWorkflowRunAttemptLogs(ctx, "o", "r", 399444496, 2, 1)
   202  	if err != nil {
   203  		t.Errorf("Actions.GetWorkflowRunAttemptLogs returned error: %v", err)
   204  	}
   205  	if resp.StatusCode != http.StatusFound {
   206  		t.Errorf("Actions.GetWorkflowRunAttemptLogs returned status: %d, want %d", resp.StatusCode, http.StatusFound)
   207  	}
   208  	want := "http://github.com/a"
   209  	if url.String() != want {
   210  		t.Errorf("Actions.GetWorkflowRunAttemptLogs returned %+v, want %+v", url.String(), want)
   211  	}
   212  
   213  	const methodName = "GetWorkflowRunAttemptLogs"
   214  	testBadOptions(t, methodName, func() (err error) {
   215  		_, _, err = client.Actions.GetWorkflowRunAttemptLogs(ctx, "\n", "\n", 399444496, 2, 1)
   216  		return err
   217  	})
   218  }
   219  
   220  func TestActionsService_GetWorkflowRunAttemptLogs_StatusMovedPermanently_dontFollowRedirects(t *testing.T) {
   221  	t.Parallel()
   222  	client, mux, _ := setup(t)
   223  
   224  	mux.HandleFunc("/repos/o/r/actions/runs/399444496/attempts/2/logs", func(w http.ResponseWriter, r *http.Request) {
   225  		testMethod(t, r, "GET")
   226  		http.Redirect(w, r, "http://github.com/a", http.StatusMovedPermanently)
   227  	})
   228  
   229  	ctx := context.Background()
   230  	_, resp, _ := client.Actions.GetWorkflowRunAttemptLogs(ctx, "o", "r", 399444496, 2, 0)
   231  	if resp.StatusCode != http.StatusMovedPermanently {
   232  		t.Errorf("Actions.GetWorkflowRunAttemptLogs returned status: %d, want %d", resp.StatusCode, http.StatusMovedPermanently)
   233  	}
   234  }
   235  
   236  func TestActionsService_GetWorkflowRunAttemptLogs_StatusMovedPermanently_followRedirects(t *testing.T) {
   237  	t.Parallel()
   238  	client, mux, serverURL := setup(t)
   239  
   240  	// Mock a redirect link, which leads to an archive link
   241  	mux.HandleFunc("/repos/o/r/actions/runs/399444496/attempts/2/logs", func(w http.ResponseWriter, r *http.Request) {
   242  		testMethod(t, r, "GET")
   243  		redirectURL, _ := url.Parse(serverURL + baseURLPath + "/redirect")
   244  		http.Redirect(w, r, redirectURL.String(), http.StatusMovedPermanently)
   245  	})
   246  
   247  	mux.HandleFunc("/redirect", func(w http.ResponseWriter, r *http.Request) {
   248  		testMethod(t, r, "GET")
   249  		http.Redirect(w, r, "http://github.com/a", http.StatusFound)
   250  	})
   251  
   252  	ctx := context.Background()
   253  	url, resp, err := client.Actions.GetWorkflowRunAttemptLogs(ctx, "o", "r", 399444496, 2, 1)
   254  	if err != nil {
   255  		t.Errorf("Actions.GetWorkflowRunAttemptLogs returned error: %v", err)
   256  	}
   257  
   258  	if resp.StatusCode != http.StatusFound {
   259  		t.Errorf("Actions.GetWorkflowRunAttemptLogs returned status: %d, want %d", resp.StatusCode, http.StatusFound)
   260  	}
   261  
   262  	want := "http://github.com/a"
   263  	if url.String() != want {
   264  		t.Errorf("Actions.GetWorkflowRunAttemptLogs returned %+v, want %+v", url.String(), want)
   265  	}
   266  
   267  	const methodName = "GetWorkflowRunAttemptLogs"
   268  	testBadOptions(t, methodName, func() (err error) {
   269  		_, _, err = client.Actions.GetWorkflowRunAttemptLogs(ctx, "\n", "\n", 399444496, 2, 1)
   270  		return err
   271  	})
   272  }
   273  
   274  func TestActionsService_RerunWorkflowRunByID(t *testing.T) {
   275  	t.Parallel()
   276  	client, mux, _ := setup(t)
   277  
   278  	mux.HandleFunc("/repos/o/r/actions/runs/3434/rerun", func(w http.ResponseWriter, r *http.Request) {
   279  		testMethod(t, r, "POST")
   280  		w.WriteHeader(http.StatusCreated)
   281  	})
   282  
   283  	ctx := context.Background()
   284  	resp, err := client.Actions.RerunWorkflowByID(ctx, "o", "r", 3434)
   285  	if err != nil {
   286  		t.Errorf("Actions.RerunWorkflowByID returned error: %v", err)
   287  	}
   288  	if resp.StatusCode != http.StatusCreated {
   289  		t.Errorf("Actions.RerunWorkflowRunByID returned status: %d, want %d", resp.StatusCode, http.StatusCreated)
   290  	}
   291  
   292  	const methodName = "RerunWorkflowByID"
   293  	testBadOptions(t, methodName, func() (err error) {
   294  		_, err = client.Actions.RerunWorkflowByID(ctx, "\n", "\n", 3434)
   295  		return err
   296  	})
   297  
   298  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   299  		return client.Actions.RerunWorkflowByID(ctx, "o", "r", 3434)
   300  	})
   301  }
   302  
   303  func TestActionsService_RerunFailedJobsByID(t *testing.T) {
   304  	t.Parallel()
   305  	client, mux, _ := setup(t)
   306  
   307  	mux.HandleFunc("/repos/o/r/actions/runs/3434/rerun-failed-jobs", func(w http.ResponseWriter, r *http.Request) {
   308  		testMethod(t, r, "POST")
   309  		w.WriteHeader(http.StatusCreated)
   310  	})
   311  
   312  	ctx := context.Background()
   313  	resp, err := client.Actions.RerunFailedJobsByID(ctx, "o", "r", 3434)
   314  	if err != nil {
   315  		t.Errorf("Actions.RerunFailedJobsByID returned error: %v", err)
   316  	}
   317  	if resp.StatusCode != http.StatusCreated {
   318  		t.Errorf("Actions.RerunFailedJobsByID returned status: %d, want %d", resp.StatusCode, http.StatusCreated)
   319  	}
   320  
   321  	const methodName = "RerunFailedJobsByID"
   322  	testBadOptions(t, methodName, func() (err error) {
   323  		_, err = client.Actions.RerunFailedJobsByID(ctx, "\n", "\n", 3434)
   324  		return err
   325  	})
   326  
   327  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   328  		return client.Actions.RerunFailedJobsByID(ctx, "o", "r", 3434)
   329  	})
   330  }
   331  
   332  func TestActionsService_RerunJobByID(t *testing.T) {
   333  	t.Parallel()
   334  	client, mux, _ := setup(t)
   335  
   336  	mux.HandleFunc("/repos/o/r/actions/jobs/3434/rerun", func(w http.ResponseWriter, r *http.Request) {
   337  		testMethod(t, r, "POST")
   338  		w.WriteHeader(http.StatusCreated)
   339  	})
   340  
   341  	ctx := context.Background()
   342  	resp, err := client.Actions.RerunJobByID(ctx, "o", "r", 3434)
   343  	if err != nil {
   344  		t.Errorf("Actions.RerunJobByID returned error: %v", err)
   345  	}
   346  	if resp.StatusCode != http.StatusCreated {
   347  		t.Errorf("Actions.RerunJobByID returned status: %d, want %d", resp.StatusCode, http.StatusCreated)
   348  	}
   349  
   350  	const methodName = "RerunJobByID"
   351  	testBadOptions(t, methodName, func() (err error) {
   352  		_, err = client.Actions.RerunJobByID(ctx, "\n", "\n", 3434)
   353  		return err
   354  	})
   355  
   356  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   357  		return client.Actions.RerunJobByID(ctx, "o", "r", 3434)
   358  	})
   359  }
   360  
   361  func TestActionsService_CancelWorkflowRunByID(t *testing.T) {
   362  	t.Parallel()
   363  	client, mux, _ := setup(t)
   364  
   365  	mux.HandleFunc("/repos/o/r/actions/runs/3434/cancel", func(w http.ResponseWriter, r *http.Request) {
   366  		testMethod(t, r, "POST")
   367  		w.WriteHeader(http.StatusAccepted)
   368  	})
   369  
   370  	ctx := context.Background()
   371  	resp, err := client.Actions.CancelWorkflowRunByID(ctx, "o", "r", 3434)
   372  	if _, ok := err.(*AcceptedError); !ok {
   373  		t.Errorf("Actions.CancelWorkflowRunByID returned error: %v (want AcceptedError)", err)
   374  	}
   375  	if resp.StatusCode != http.StatusAccepted {
   376  		t.Errorf("Actions.CancelWorkflowRunByID returned status: %d, want %d", resp.StatusCode, http.StatusAccepted)
   377  	}
   378  
   379  	const methodName = "CancelWorkflowRunByID"
   380  	testBadOptions(t, methodName, func() (err error) {
   381  		_, err = client.Actions.CancelWorkflowRunByID(ctx, "\n", "\n", 3434)
   382  		return err
   383  	})
   384  
   385  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   386  		return client.Actions.CancelWorkflowRunByID(ctx, "o", "r", 3434)
   387  	})
   388  }
   389  
   390  func TestActionsService_GetWorkflowRunLogs(t *testing.T) {
   391  	t.Parallel()
   392  	client, mux, _ := setup(t)
   393  
   394  	mux.HandleFunc("/repos/o/r/actions/runs/399444496/logs", func(w http.ResponseWriter, r *http.Request) {
   395  		testMethod(t, r, "GET")
   396  		http.Redirect(w, r, "http://github.com/a", http.StatusFound)
   397  	})
   398  
   399  	ctx := context.Background()
   400  	url, resp, err := client.Actions.GetWorkflowRunLogs(ctx, "o", "r", 399444496, 1)
   401  	if err != nil {
   402  		t.Errorf("Actions.GetWorkflowRunLogs returned error: %v", err)
   403  	}
   404  	if resp.StatusCode != http.StatusFound {
   405  		t.Errorf("Actions.GetWorkflowRunLogs returned status: %d, want %d", resp.StatusCode, http.StatusFound)
   406  	}
   407  	want := "http://github.com/a"
   408  	if url.String() != want {
   409  		t.Errorf("Actions.GetWorkflowRunLogs returned %+v, want %+v", url.String(), want)
   410  	}
   411  
   412  	const methodName = "GetWorkflowRunLogs"
   413  	testBadOptions(t, methodName, func() (err error) {
   414  		_, _, err = client.Actions.GetWorkflowRunLogs(ctx, "\n", "\n", 399444496, 1)
   415  		return err
   416  	})
   417  }
   418  
   419  func TestActionsService_GetWorkflowRunLogs_StatusMovedPermanently_dontFollowRedirects(t *testing.T) {
   420  	t.Parallel()
   421  	client, mux, _ := setup(t)
   422  
   423  	mux.HandleFunc("/repos/o/r/actions/runs/399444496/logs", func(w http.ResponseWriter, r *http.Request) {
   424  		testMethod(t, r, "GET")
   425  		http.Redirect(w, r, "http://github.com/a", http.StatusMovedPermanently)
   426  	})
   427  
   428  	ctx := context.Background()
   429  	_, resp, _ := client.Actions.GetWorkflowRunLogs(ctx, "o", "r", 399444496, 0)
   430  	if resp.StatusCode != http.StatusMovedPermanently {
   431  		t.Errorf("Actions.GetWorkflowJobLogs returned status: %d, want %d", resp.StatusCode, http.StatusMovedPermanently)
   432  	}
   433  }
   434  
   435  func TestActionsService_GetWorkflowRunLogs_StatusMovedPermanently_followRedirects(t *testing.T) {
   436  	t.Parallel()
   437  	client, mux, serverURL := setup(t)
   438  
   439  	// Mock a redirect link, which leads to an archive link
   440  	mux.HandleFunc("/repos/o/r/actions/runs/399444496/logs", func(w http.ResponseWriter, r *http.Request) {
   441  		testMethod(t, r, "GET")
   442  		redirectURL, _ := url.Parse(serverURL + baseURLPath + "/redirect")
   443  		http.Redirect(w, r, redirectURL.String(), http.StatusMovedPermanently)
   444  	})
   445  
   446  	mux.HandleFunc("/redirect", func(w http.ResponseWriter, r *http.Request) {
   447  		testMethod(t, r, "GET")
   448  		http.Redirect(w, r, "http://github.com/a", http.StatusFound)
   449  	})
   450  
   451  	ctx := context.Background()
   452  	url, resp, err := client.Actions.GetWorkflowRunLogs(ctx, "o", "r", 399444496, 1)
   453  	if err != nil {
   454  		t.Errorf("Actions.GetWorkflowJobLogs returned error: %v", err)
   455  	}
   456  
   457  	if resp.StatusCode != http.StatusFound {
   458  		t.Errorf("Actions.GetWorkflowJobLogs returned status: %d, want %d", resp.StatusCode, http.StatusFound)
   459  	}
   460  
   461  	want := "http://github.com/a"
   462  	if url.String() != want {
   463  		t.Errorf("Actions.GetWorkflowJobLogs returned %+v, want %+v", url.String(), want)
   464  	}
   465  
   466  	const methodName = "GetWorkflowRunLogs"
   467  	testBadOptions(t, methodName, func() (err error) {
   468  		_, _, err = client.Actions.GetWorkflowRunLogs(ctx, "\n", "\n", 399444496, 1)
   469  		return err
   470  	})
   471  }
   472  
   473  func TestActionService_ListRepositoryWorkflowRuns(t *testing.T) {
   474  	t.Parallel()
   475  	client, mux, _ := setup(t)
   476  
   477  	mux.HandleFunc("/repos/o/r/actions/runs", func(w http.ResponseWriter, r *http.Request) {
   478  		testMethod(t, r, "GET")
   479  		testFormValues(t, r, values{"per_page": "2", "page": "2"})
   480  		fmt.Fprint(w, `{"total_count":2,
   481  		"workflow_runs":[
   482  			{"id":298499444,"run_number":301,"created_at":"2020-04-11T11:14:54Z","updated_at":"2020-04-11T11:14:54Z"},
   483  			{"id":298499445,"run_number":302,"created_at":"2020-04-11T11:14:54Z","updated_at":"2020-04-11T11:14:54Z"}]}`)
   484  	})
   485  
   486  	opts := &ListWorkflowRunsOptions{ListOptions: ListOptions{Page: 2, PerPage: 2}}
   487  	ctx := context.Background()
   488  	runs, _, err := client.Actions.ListRepositoryWorkflowRuns(ctx, "o", "r", opts)
   489  	if err != nil {
   490  		t.Errorf("Actions.ListRepositoryWorkflowRuns returned error: %v", err)
   491  	}
   492  
   493  	expected := &WorkflowRuns{
   494  		TotalCount: Int(2),
   495  		WorkflowRuns: []*WorkflowRun{
   496  			{ID: Int64(298499444), RunNumber: Int(301), CreatedAt: &Timestamp{time.Date(2020, time.April, 11, 11, 14, 54, 0, time.UTC)}, UpdatedAt: &Timestamp{time.Date(2020, time.April, 11, 11, 14, 54, 0, time.UTC)}},
   497  			{ID: Int64(298499445), RunNumber: Int(302), CreatedAt: &Timestamp{time.Date(2020, time.April, 11, 11, 14, 54, 0, time.UTC)}, UpdatedAt: &Timestamp{time.Date(2020, time.April, 11, 11, 14, 54, 0, time.UTC)}},
   498  		},
   499  	}
   500  
   501  	if !cmp.Equal(runs, expected) {
   502  		t.Errorf("Actions.ListRepositoryWorkflowRuns returned %+v, want %+v", runs, expected)
   503  	}
   504  
   505  	const methodName = "ListRepositoryWorkflowRuns"
   506  	testBadOptions(t, methodName, func() (err error) {
   507  		_, _, err = client.Actions.ListRepositoryWorkflowRuns(ctx, "\n", "\n", opts)
   508  
   509  		return err
   510  	})
   511  
   512  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   513  		got, resp, err := client.Actions.ListRepositoryWorkflowRuns(ctx, "o", "r", opts)
   514  
   515  		if got != nil {
   516  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   517  		}
   518  		return resp, err
   519  	})
   520  }
   521  
   522  func TestActionService_DeleteWorkflowRun(t *testing.T) {
   523  	t.Parallel()
   524  	client, mux, _ := setup(t)
   525  
   526  	mux.HandleFunc("/repos/o/r/actions/runs/399444496", func(w http.ResponseWriter, r *http.Request) {
   527  		testMethod(t, r, "DELETE")
   528  
   529  		w.WriteHeader(http.StatusNoContent)
   530  	})
   531  
   532  	ctx := context.Background()
   533  	if _, err := client.Actions.DeleteWorkflowRun(ctx, "o", "r", 399444496); err != nil {
   534  		t.Errorf("DeleteWorkflowRun returned error: %v", err)
   535  	}
   536  
   537  	const methodName = "DeleteWorkflowRun"
   538  	testBadOptions(t, methodName, func() (err error) {
   539  		_, err = client.Actions.DeleteWorkflowRun(ctx, "\n", "\n", 399444496)
   540  		return err
   541  	})
   542  
   543  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   544  		return client.Actions.DeleteWorkflowRun(ctx, "o", "r", 399444496)
   545  	})
   546  }
   547  
   548  func TestActionService_DeleteWorkflowRunLogs(t *testing.T) {
   549  	t.Parallel()
   550  	client, mux, _ := setup(t)
   551  
   552  	mux.HandleFunc("/repos/o/r/actions/runs/399444496/logs", func(w http.ResponseWriter, r *http.Request) {
   553  		testMethod(t, r, "DELETE")
   554  
   555  		w.WriteHeader(http.StatusNoContent)
   556  	})
   557  
   558  	ctx := context.Background()
   559  	if _, err := client.Actions.DeleteWorkflowRunLogs(ctx, "o", "r", 399444496); err != nil {
   560  		t.Errorf("DeleteWorkflowRunLogs returned error: %v", err)
   561  	}
   562  
   563  	const methodName = "DeleteWorkflowRunLogs"
   564  	testBadOptions(t, methodName, func() (err error) {
   565  		_, err = client.Actions.DeleteWorkflowRunLogs(ctx, "\n", "\n", 399444496)
   566  		return err
   567  	})
   568  
   569  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   570  		return client.Actions.DeleteWorkflowRunLogs(ctx, "o", "r", 399444496)
   571  	})
   572  }
   573  
   574  func TestPendingDeployment_Marshal(t *testing.T) {
   575  	t.Parallel()
   576  	testJSONMarshal(t, &PendingDeployment{}, "{}")
   577  
   578  	u := &PendingDeployment{
   579  		Environment: &PendingDeploymentEnvironment{
   580  			ID:      Int64(1),
   581  			NodeID:  String("nid"),
   582  			Name:    String("n"),
   583  			URL:     String("u"),
   584  			HTMLURL: String("hu"),
   585  		},
   586  		WaitTimer:             Int64(100),
   587  		WaitTimerStartedAt:    &Timestamp{referenceTime},
   588  		CurrentUserCanApprove: Bool(false),
   589  		Reviewers: []*RequiredReviewer{
   590  			{
   591  				Type: String("User"),
   592  				Reviewer: &User{
   593  					Login: String("l"),
   594  				},
   595  			},
   596  			{
   597  				Type: String("Team"),
   598  				Reviewer: &Team{
   599  					Name: String("n"),
   600  				},
   601  			},
   602  		},
   603  	}
   604  	want := `{
   605  		"environment": {
   606  			"id": 1,
   607  			"node_id": "nid",
   608  			"name": "n",
   609  			"url": "u",
   610  			"html_url": "hu"
   611  		},
   612  		"wait_timer": 100,
   613  		"wait_timer_started_at": ` + referenceTimeStr + `,
   614  		"current_user_can_approve": false,
   615  		"reviewers": [
   616  			{
   617  				"type": "User",
   618  				"reviewer": {
   619  					"login": "l"
   620  				}
   621  			},
   622  			{
   623  				"type": "Team",
   624  				"reviewer": {
   625  					"name": "n"
   626  				}
   627  			}
   628  		]
   629  	}`
   630  	testJSONMarshal(t, u, want)
   631  }
   632  
   633  func TestActionsService_ReviewCustomDeploymentProtectionRule(t *testing.T) {
   634  	t.Parallel()
   635  	client, mux, _ := setup(t)
   636  
   637  	mux.HandleFunc("/repos/o/r/actions/runs/9444496/deployment_protection_rule", func(w http.ResponseWriter, r *http.Request) {
   638  		testMethod(t, r, "POST")
   639  
   640  		w.WriteHeader(http.StatusNoContent)
   641  	})
   642  
   643  	request := ReviewCustomDeploymentProtectionRuleRequest{
   644  		EnvironmentName: "production",
   645  		State:           "approved",
   646  		Comment:         "Approve deployment",
   647  	}
   648  
   649  	ctx := context.Background()
   650  	if _, err := client.Actions.ReviewCustomDeploymentProtectionRule(ctx, "o", "r", 9444496, &request); err != nil {
   651  		t.Errorf("ReviewCustomDeploymentProtectionRule returned error: %v", err)
   652  	}
   653  
   654  	const methodName = "ReviewCustomDeploymentProtectionRule"
   655  	testBadOptions(t, methodName, func() (err error) {
   656  		_, err = client.Actions.ReviewCustomDeploymentProtectionRule(ctx, "\n", "\n", 9444496, &request)
   657  		return err
   658  	})
   659  
   660  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   661  		return client.Actions.ReviewCustomDeploymentProtectionRule(ctx, "o", "r", 9444496, &request)
   662  	})
   663  }
   664  
   665  func TestReviewCustomDeploymentProtectionRuleRequest_Marshal(t *testing.T) {
   666  	t.Parallel()
   667  	testJSONMarshal(t, &ReviewCustomDeploymentProtectionRuleRequest{}, "{}")
   668  
   669  	r := &ReviewCustomDeploymentProtectionRuleRequest{
   670  		EnvironmentName: "e",
   671  		State:           "rejected",
   672  		Comment:         "c",
   673  	}
   674  	want := `{
   675  		"environment_name": "e",
   676  		"state": "rejected",
   677  		"comment": "c"
   678  	}`
   679  	testJSONMarshal(t, r, want)
   680  }
   681  
   682  func TestActionsService_GetWorkflowRunUsageByID(t *testing.T) {
   683  	t.Parallel()
   684  	client, mux, _ := setup(t)
   685  
   686  	mux.HandleFunc("/repos/o/r/actions/runs/29679449/timing", func(w http.ResponseWriter, r *http.Request) {
   687  		testMethod(t, r, "GET")
   688  		fmt.Fprint(w, `{"billable":{"UBUNTU":{"total_ms":180000,"jobs":1,"job_runs":[{"job_id":1,"duration_ms":60000}]},"MACOS":{"total_ms":240000,"jobs":2,"job_runs":[{"job_id":2,"duration_ms":30000},{"job_id":3,"duration_ms":10000}]},"WINDOWS":{"total_ms":300000,"jobs":2}},"run_duration_ms":500000}`)
   689  	})
   690  
   691  	ctx := context.Background()
   692  	workflowRunUsage, _, err := client.Actions.GetWorkflowRunUsageByID(ctx, "o", "r", 29679449)
   693  	if err != nil {
   694  		t.Errorf("Actions.GetWorkflowRunUsageByID returned error: %v", err)
   695  	}
   696  
   697  	want := &WorkflowRunUsage{
   698  		Billable: &WorkflowRunBillMap{
   699  			"UBUNTU": &WorkflowRunBill{
   700  				TotalMS: Int64(180000),
   701  				Jobs:    Int(1),
   702  				JobRuns: []*WorkflowRunJobRun{
   703  					{
   704  						JobID:      Int(1),
   705  						DurationMS: Int64(60000),
   706  					},
   707  				},
   708  			},
   709  			"MACOS": &WorkflowRunBill{
   710  				TotalMS: Int64(240000),
   711  				Jobs:    Int(2),
   712  				JobRuns: []*WorkflowRunJobRun{
   713  					{
   714  						JobID:      Int(2),
   715  						DurationMS: Int64(30000),
   716  					},
   717  					{
   718  						JobID:      Int(3),
   719  						DurationMS: Int64(10000),
   720  					},
   721  				},
   722  			},
   723  			"WINDOWS": &WorkflowRunBill{
   724  				TotalMS: Int64(300000),
   725  				Jobs:    Int(2),
   726  			},
   727  		},
   728  		RunDurationMS: Int64(500000),
   729  	}
   730  
   731  	if !cmp.Equal(workflowRunUsage, want) {
   732  		t.Errorf("Actions.GetWorkflowRunUsageByID returned %+v, want %+v", workflowRunUsage, want)
   733  	}
   734  
   735  	const methodName = "GetWorkflowRunUsageByID"
   736  	testBadOptions(t, methodName, func() (err error) {
   737  		_, _, err = client.Actions.GetWorkflowRunUsageByID(ctx, "\n", "\n", 29679449)
   738  		return err
   739  	})
   740  
   741  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   742  		got, resp, err := client.Actions.GetWorkflowRunUsageByID(ctx, "o", "r", 29679449)
   743  		if got != nil {
   744  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   745  		}
   746  		return resp, err
   747  	})
   748  }
   749  
   750  func TestWorkflowRun_Marshal(t *testing.T) {
   751  	t.Parallel()
   752  	testJSONMarshal(t, &WorkflowRun{}, "{}")
   753  
   754  	u := &WorkflowRun{
   755  		ID:         Int64(1),
   756  		Name:       String("n"),
   757  		NodeID:     String("nid"),
   758  		HeadBranch: String("hb"),
   759  		HeadSHA:    String("hs"),
   760  		Path:       String("p"),
   761  		RunNumber:  Int(1),
   762  		RunAttempt: Int(1),
   763  		Event:      String("e"),
   764  		Status:     String("s"),
   765  		Conclusion: String("c"),
   766  		WorkflowID: Int64(1),
   767  		URL:        String("u"),
   768  		HTMLURL:    String("h"),
   769  		PullRequests: []*PullRequest{
   770  			{
   771  				URL:    String("u"),
   772  				ID:     Int64(1),
   773  				Number: Int(1),
   774  				Head: &PullRequestBranch{
   775  					Ref: String("r"),
   776  					SHA: String("s"),
   777  					Repo: &Repository{
   778  						ID:   Int64(1),
   779  						URL:  String("s"),
   780  						Name: String("n"),
   781  					},
   782  				},
   783  				Base: &PullRequestBranch{
   784  					Ref: String("r"),
   785  					SHA: String("s"),
   786  					Repo: &Repository{
   787  						ID:   Int64(1),
   788  						URL:  String("u"),
   789  						Name: String("n"),
   790  					},
   791  				},
   792  			},
   793  		},
   794  		CreatedAt:          &Timestamp{referenceTime},
   795  		UpdatedAt:          &Timestamp{referenceTime},
   796  		RunStartedAt:       &Timestamp{referenceTime},
   797  		JobsURL:            String("j"),
   798  		LogsURL:            String("l"),
   799  		CheckSuiteURL:      String("c"),
   800  		ArtifactsURL:       String("a"),
   801  		CancelURL:          String("c"),
   802  		RerunURL:           String("r"),
   803  		PreviousAttemptURL: String("p"),
   804  		HeadCommit: &HeadCommit{
   805  			Message: String("m"),
   806  			Author: &CommitAuthor{
   807  				Name:  String("n"),
   808  				Email: String("e"),
   809  				Login: String("l"),
   810  			},
   811  			URL:       String("u"),
   812  			Distinct:  Bool(false),
   813  			SHA:       String("s"),
   814  			ID:        String("i"),
   815  			TreeID:    String("tid"),
   816  			Timestamp: &Timestamp{referenceTime},
   817  			Committer: &CommitAuthor{
   818  				Name:  String("n"),
   819  				Email: String("e"),
   820  				Login: String("l"),
   821  			},
   822  		},
   823  		WorkflowURL: String("w"),
   824  		Repository: &Repository{
   825  			ID:   Int64(1),
   826  			URL:  String("u"),
   827  			Name: String("n"),
   828  		},
   829  		HeadRepository: &Repository{
   830  			ID:   Int64(1),
   831  			URL:  String("u"),
   832  			Name: String("n"),
   833  		},
   834  		Actor: &User{
   835  			Login:           String("l"),
   836  			ID:              Int64(1),
   837  			AvatarURL:       String("a"),
   838  			GravatarID:      String("g"),
   839  			Name:            String("n"),
   840  			Company:         String("c"),
   841  			Blog:            String("b"),
   842  			Location:        String("l"),
   843  			Email:           String("e"),
   844  			Hireable:        Bool(true),
   845  			Bio:             String("b"),
   846  			TwitterUsername: String("t"),
   847  			PublicRepos:     Int(1),
   848  			Followers:       Int(1),
   849  			Following:       Int(1),
   850  			CreatedAt:       &Timestamp{referenceTime},
   851  			SuspendedAt:     &Timestamp{referenceTime},
   852  			URL:             String("u"),
   853  		},
   854  		TriggeringActor: &User{
   855  			Login:           String("l2"),
   856  			ID:              Int64(2),
   857  			AvatarURL:       String("a2"),
   858  			GravatarID:      String("g2"),
   859  			Name:            String("n2"),
   860  			Company:         String("c2"),
   861  			Blog:            String("b2"),
   862  			Location:        String("l2"),
   863  			Email:           String("e2"),
   864  			Hireable:        Bool(false),
   865  			Bio:             String("b2"),
   866  			TwitterUsername: String("t2"),
   867  			PublicRepos:     Int(2),
   868  			Followers:       Int(2),
   869  			Following:       Int(2),
   870  			CreatedAt:       &Timestamp{referenceTime},
   871  			SuspendedAt:     &Timestamp{referenceTime},
   872  			URL:             String("u2"),
   873  		},
   874  		ReferencedWorkflows: []*ReferencedWorkflow{
   875  			{
   876  				Path: String("rwfp"),
   877  				SHA:  String("rwfsha"),
   878  				Ref:  String("rwfref"),
   879  			},
   880  		},
   881  	}
   882  
   883  	want := `{
   884  		"id": 1,
   885  		"name": "n",
   886  		"node_id": "nid",
   887  		"head_branch": "hb",
   888  		"head_sha": "hs",
   889  		"path": "p",
   890  		"run_number": 1,
   891  		"run_attempt": 1,
   892  		"event": "e",
   893  		"status": "s",
   894  		"conclusion": "c",
   895  		"workflow_id": 1,
   896  		"url": "u",
   897  		"html_url": "h",
   898  		"pull_requests": [
   899  			{
   900  				"id":1,
   901  				"number":1,
   902  				"url":"u",
   903  				"head":{
   904  					"ref":"r",
   905  					"sha":"s",
   906  					"repo": {
   907  						"id":1,
   908  						"name":"n",
   909  						"url":"s"
   910  						}
   911  					},
   912  					"base": {
   913  						"ref":"r",
   914  						"sha":"s",
   915  						"repo": {
   916  							"id":1,
   917  							"name":"n",
   918  							"url":"u"
   919  						}
   920  					}
   921  			}
   922  		],
   923  		"created_at": ` + referenceTimeStr + `,
   924  		"updated_at": ` + referenceTimeStr + `,
   925  		"run_started_at": ` + referenceTimeStr + `,
   926  		"jobs_url": "j",
   927  		"logs_url": "l",
   928  		"check_suite_url": "c",
   929  		"artifacts_url": "a",
   930  		"cancel_url": "c",
   931  		"rerun_url": "r",
   932  		"previous_attempt_url": "p",
   933  		"head_commit": {
   934  			"message": "m",
   935  			"author": {
   936  				"name": "n",
   937  				"email": "e",
   938  				"username": "l"
   939  			},
   940  			"url": "u",
   941  			"distinct": false,
   942  			"sha": "s",
   943  			"id": "i",
   944  			"tree_id": "tid",
   945  			"timestamp": ` + referenceTimeStr + `,
   946  			"committer": {
   947  				"name": "n",
   948  				"email": "e",
   949  				"username": "l"
   950  			}
   951  		},
   952  		"workflow_url": "w",
   953  		"repository": {
   954  			"id": 1,
   955  			"url": "u",
   956  			"name": "n"
   957  		},
   958  		"head_repository": {
   959  			"id": 1,
   960  			"url": "u",
   961  			"name": "n"
   962  		},
   963  		"actor": {
   964  			"login": "l",
   965  			"id": 1,
   966  			"avatar_url": "a",
   967  			"gravatar_id": "g",
   968  			"name": "n",
   969  			"company": "c",
   970  			"blog": "b",
   971  			"location": "l",
   972  			"email": "e",
   973  			"hireable": true,
   974  			"bio": "b",
   975  			"twitter_username": "t",
   976  			"public_repos": 1,
   977  			"followers": 1,
   978  			"following": 1,
   979  			"created_at": ` + referenceTimeStr + `,
   980  			"suspended_at": ` + referenceTimeStr + `,
   981  			"url": "u"
   982  		},
   983  		"triggering_actor": {
   984  			"login": "l2",
   985  			"id": 2,
   986  			"avatar_url": "a2",
   987  			"gravatar_id": "g2",
   988  			"name": "n2",
   989  			"company": "c2",
   990  			"blog": "b2",
   991  			"location": "l2",
   992  			"email": "e2",
   993  			"hireable": false,
   994  			"bio": "b2",
   995  			"twitter_username": "t2",
   996  			"public_repos": 2,
   997  			"followers": 2,
   998  			"following": 2,
   999  			"created_at": ` + referenceTimeStr + `,
  1000  			"suspended_at": ` + referenceTimeStr + `,
  1001  			"url": "u2"
  1002  		},
  1003  		"referenced_workflows": [
  1004  			{
  1005  				"path": "rwfp",
  1006  				"sha": "rwfsha",
  1007  				"ref": "rwfref"
  1008  			}
  1009  		]
  1010  	}`
  1011  
  1012  	testJSONMarshal(t, u, want)
  1013  }
  1014  
  1015  func TestWorkflowRuns_Marshal(t *testing.T) {
  1016  	t.Parallel()
  1017  	testJSONMarshal(t, &WorkflowRuns{}, "{}")
  1018  
  1019  	u := &WorkflowRuns{
  1020  		TotalCount: Int(1),
  1021  		WorkflowRuns: []*WorkflowRun{
  1022  			{
  1023  				ID:         Int64(1),
  1024  				Name:       String("n"),
  1025  				NodeID:     String("nid"),
  1026  				HeadBranch: String("hb"),
  1027  				HeadSHA:    String("hs"),
  1028  				RunNumber:  Int(1),
  1029  				RunAttempt: Int(1),
  1030  				Event:      String("e"),
  1031  				Status:     String("s"),
  1032  				Conclusion: String("c"),
  1033  				WorkflowID: Int64(1),
  1034  				URL:        String("u"),
  1035  				HTMLURL:    String("h"),
  1036  				PullRequests: []*PullRequest{
  1037  					{
  1038  						URL:    String("u"),
  1039  						ID:     Int64(1),
  1040  						Number: Int(1),
  1041  						Head: &PullRequestBranch{
  1042  							Ref: String("r"),
  1043  							SHA: String("s"),
  1044  							Repo: &Repository{
  1045  								ID:   Int64(1),
  1046  								URL:  String("s"),
  1047  								Name: String("n"),
  1048  							},
  1049  						},
  1050  						Base: &PullRequestBranch{
  1051  							Ref: String("r"),
  1052  							SHA: String("s"),
  1053  							Repo: &Repository{
  1054  								ID:   Int64(1),
  1055  								URL:  String("u"),
  1056  								Name: String("n"),
  1057  							},
  1058  						},
  1059  					},
  1060  				},
  1061  				CreatedAt:          &Timestamp{referenceTime},
  1062  				UpdatedAt:          &Timestamp{referenceTime},
  1063  				RunStartedAt:       &Timestamp{referenceTime},
  1064  				JobsURL:            String("j"),
  1065  				LogsURL:            String("l"),
  1066  				CheckSuiteURL:      String("c"),
  1067  				ArtifactsURL:       String("a"),
  1068  				CancelURL:          String("c"),
  1069  				RerunURL:           String("r"),
  1070  				PreviousAttemptURL: String("p"),
  1071  				HeadCommit: &HeadCommit{
  1072  					Message: String("m"),
  1073  					Author: &CommitAuthor{
  1074  						Name:  String("n"),
  1075  						Email: String("e"),
  1076  						Login: String("l"),
  1077  					},
  1078  					URL:       String("u"),
  1079  					Distinct:  Bool(false),
  1080  					SHA:       String("s"),
  1081  					ID:        String("i"),
  1082  					TreeID:    String("tid"),
  1083  					Timestamp: &Timestamp{referenceTime},
  1084  					Committer: &CommitAuthor{
  1085  						Name:  String("n"),
  1086  						Email: String("e"),
  1087  						Login: String("l"),
  1088  					},
  1089  				},
  1090  				WorkflowURL: String("w"),
  1091  				Repository: &Repository{
  1092  					ID:   Int64(1),
  1093  					URL:  String("u"),
  1094  					Name: String("n"),
  1095  				},
  1096  				HeadRepository: &Repository{
  1097  					ID:   Int64(1),
  1098  					URL:  String("u"),
  1099  					Name: String("n"),
  1100  				},
  1101  				Actor: &User{
  1102  					Login:           String("l"),
  1103  					ID:              Int64(1),
  1104  					AvatarURL:       String("a"),
  1105  					GravatarID:      String("g"),
  1106  					Name:            String("n"),
  1107  					Company:         String("c"),
  1108  					Blog:            String("b"),
  1109  					Location:        String("l"),
  1110  					Email:           String("e"),
  1111  					Hireable:        Bool(true),
  1112  					Bio:             String("b"),
  1113  					TwitterUsername: String("t"),
  1114  					PublicRepos:     Int(1),
  1115  					Followers:       Int(1),
  1116  					Following:       Int(1),
  1117  					CreatedAt:       &Timestamp{referenceTime},
  1118  					SuspendedAt:     &Timestamp{referenceTime},
  1119  					URL:             String("u"),
  1120  				},
  1121  				TriggeringActor: &User{
  1122  					Login:           String("l2"),
  1123  					ID:              Int64(2),
  1124  					AvatarURL:       String("a2"),
  1125  					GravatarID:      String("g2"),
  1126  					Name:            String("n2"),
  1127  					Company:         String("c2"),
  1128  					Blog:            String("b2"),
  1129  					Location:        String("l2"),
  1130  					Email:           String("e2"),
  1131  					Hireable:        Bool(false),
  1132  					Bio:             String("b2"),
  1133  					TwitterUsername: String("t2"),
  1134  					PublicRepos:     Int(2),
  1135  					Followers:       Int(2),
  1136  					Following:       Int(2),
  1137  					CreatedAt:       &Timestamp{referenceTime},
  1138  					SuspendedAt:     &Timestamp{referenceTime},
  1139  					URL:             String("u2"),
  1140  				},
  1141  			},
  1142  		},
  1143  	}
  1144  
  1145  	want := `{
  1146  		"total_count": 1,
  1147  		"workflow_runs": [
  1148  			{
  1149  				"id": 1,
  1150  				"name": "n",
  1151  				"node_id": "nid",
  1152  				"head_branch": "hb",
  1153  				"head_sha": "hs",
  1154  				"run_number": 1,
  1155  				"run_attempt": 1,
  1156  				"event": "e",
  1157  				"status": "s",
  1158  				"conclusion": "c",
  1159  				"workflow_id": 1,
  1160  				"url": "u",
  1161  				"html_url": "h",
  1162  				"pull_requests": [
  1163  					{
  1164  						"id":1,
  1165  						"number":1,
  1166  						"url":"u",
  1167  						"head":{
  1168  							"ref":"r",
  1169  							"sha":"s",
  1170  							"repo": {
  1171  								"id":1,
  1172  								"name":"n",
  1173  								"url":"s"
  1174  								}
  1175  							},
  1176  							"base": {
  1177  								"ref":"r",
  1178  								"sha":"s",
  1179  								"repo": {
  1180  									"id":1,
  1181  									"name":"n",
  1182  									"url":"u"
  1183  								}
  1184  							}
  1185  					}
  1186  				],
  1187  				"created_at": ` + referenceTimeStr + `,
  1188  				"updated_at": ` + referenceTimeStr + `,
  1189  				"run_started_at": ` + referenceTimeStr + `,
  1190  				"jobs_url": "j",
  1191  				"logs_url": "l",
  1192  				"check_suite_url": "c",
  1193  				"artifacts_url": "a",
  1194  				"cancel_url": "c",
  1195  				"rerun_url": "r",
  1196  				"previous_attempt_url": "p",
  1197  				"head_commit": {
  1198  					"message": "m",
  1199  					"author": {
  1200  						"name": "n",
  1201  						"email": "e",
  1202  						"username": "l"
  1203  					},
  1204  					"url": "u",
  1205  					"distinct": false,
  1206  					"sha": "s",
  1207  					"id": "i",
  1208  					"tree_id": "tid",
  1209  					"timestamp": ` + referenceTimeStr + `,
  1210  					"committer": {
  1211  						"name": "n",
  1212  						"email": "e",
  1213  						"username": "l"
  1214  					}
  1215  				},
  1216  				"workflow_url": "w",
  1217  				"repository": {
  1218  					"id": 1,
  1219  					"url": "u",
  1220  					"name": "n"
  1221  				},
  1222  				"head_repository": {
  1223  					"id": 1,
  1224  					"url": "u",
  1225  					"name": "n"
  1226  				},
  1227  				"actor": {
  1228  					"login": "l",
  1229  					"id": 1,
  1230  					"avatar_url": "a",
  1231  					"gravatar_id": "g",
  1232  					"name": "n",
  1233  					"company": "c",
  1234  					"blog": "b",
  1235  					"location": "l",
  1236  					"email": "e",
  1237  					"hireable": true,
  1238  					"bio": "b",
  1239  					"twitter_username": "t",
  1240  					"public_repos": 1,
  1241  					"followers": 1,
  1242  					"following": 1,
  1243  					"created_at": ` + referenceTimeStr + `,
  1244  					"suspended_at": ` + referenceTimeStr + `,
  1245  					"url": "u"
  1246  				},
  1247  				"triggering_actor": {
  1248  					"login": "l2",
  1249  					"id": 2,
  1250  					"avatar_url": "a2",
  1251  					"gravatar_id": "g2",
  1252  					"name": "n2",
  1253  					"company": "c2",
  1254  					"blog": "b2",
  1255  					"location": "l2",
  1256  					"email": "e2",
  1257  					"hireable": false,
  1258  					"bio": "b2",
  1259  					"twitter_username": "t2",
  1260  					"public_repos": 2,
  1261  					"followers": 2,
  1262  					"following": 2,
  1263  					"created_at": ` + referenceTimeStr + `,
  1264  					"suspended_at": ` + referenceTimeStr + `,
  1265  					"url": "u2"
  1266  				}
  1267  			}
  1268  		]
  1269  	}`
  1270  
  1271  	testJSONMarshal(t, u, want)
  1272  }
  1273  
  1274  func TestWorkflowRunBill_Marshal(t *testing.T) {
  1275  	t.Parallel()
  1276  	testJSONMarshal(t, &WorkflowRunBill{}, "{}")
  1277  
  1278  	u := &WorkflowRunBill{
  1279  		TotalMS: Int64(1),
  1280  		Jobs:    Int(1),
  1281  	}
  1282  
  1283  	want := `{
  1284  		"total_ms": 1,
  1285  		"jobs": 1
  1286  	}`
  1287  
  1288  	testJSONMarshal(t, u, want)
  1289  }
  1290  
  1291  func TestWorkflowRunBillMap_Marshal(t *testing.T) {
  1292  	t.Parallel()
  1293  	testJSONMarshal(t, &WorkflowRunBillMap{}, "{}")
  1294  
  1295  	u := &WorkflowRunBillMap{
  1296  		"UBUNTU": &WorkflowRunBill{
  1297  			TotalMS: Int64(1),
  1298  			Jobs:    Int(1),
  1299  		},
  1300  		"MACOS": &WorkflowRunBill{
  1301  			TotalMS: Int64(1),
  1302  			Jobs:    Int(1),
  1303  		},
  1304  		"WINDOWS": &WorkflowRunBill{
  1305  			TotalMS: Int64(1),
  1306  			Jobs:    Int(1),
  1307  		},
  1308  	}
  1309  
  1310  	want := `{
  1311  		"UBUNTU": {
  1312  			"total_ms": 1,
  1313  			"jobs": 1
  1314  		},
  1315  		"MACOS": {
  1316  			"total_ms": 1,
  1317  			"jobs": 1
  1318  		},
  1319  		"WINDOWS": {
  1320  			"total_ms": 1,
  1321  			"jobs": 1
  1322  		}
  1323  	}`
  1324  
  1325  	testJSONMarshal(t, u, want)
  1326  }
  1327  
  1328  func TestWorkflowRunUsage_Marshal(t *testing.T) {
  1329  	t.Parallel()
  1330  	testJSONMarshal(t, &WorkflowRunUsage{}, "{}")
  1331  
  1332  	u := &WorkflowRunUsage{
  1333  		Billable: &WorkflowRunBillMap{
  1334  			"UBUNTU": &WorkflowRunBill{
  1335  				TotalMS: Int64(1),
  1336  				Jobs:    Int(1),
  1337  			},
  1338  			"MACOS": &WorkflowRunBill{
  1339  				TotalMS: Int64(1),
  1340  				Jobs:    Int(1),
  1341  			},
  1342  			"WINDOWS": &WorkflowRunBill{
  1343  				TotalMS: Int64(1),
  1344  				Jobs:    Int(1),
  1345  			},
  1346  		},
  1347  		RunDurationMS: Int64(1),
  1348  	}
  1349  
  1350  	want := `{
  1351  		"billable": {
  1352  			"UBUNTU": {
  1353  				"total_ms": 1,
  1354  				"jobs": 1
  1355  			},
  1356  			"MACOS": {
  1357  				"total_ms": 1,
  1358  				"jobs": 1
  1359  			},
  1360  			"WINDOWS": {
  1361  				"total_ms": 1,
  1362  				"jobs": 1
  1363  			}
  1364  		},
  1365  		"run_duration_ms": 1
  1366  	}`
  1367  
  1368  	testJSONMarshal(t, u, want)
  1369  }
  1370  
  1371  func TestActionService_PendingDeployments(t *testing.T) {
  1372  	t.Parallel()
  1373  	client, mux, _ := setup(t)
  1374  
  1375  	input := &PendingDeploymentsRequest{EnvironmentIDs: []int64{3, 4}, State: "approved", Comment: ""}
  1376  
  1377  	mux.HandleFunc("/repos/o/r/actions/runs/399444496/pending_deployments", func(w http.ResponseWriter, r *http.Request) {
  1378  		v := new(PendingDeploymentsRequest)
  1379  		assertNilError(t, json.NewDecoder(r.Body).Decode(v))
  1380  
  1381  		testMethod(t, r, "POST")
  1382  		if !cmp.Equal(v, input) {
  1383  			t.Errorf("Request body = %+v, want %+v", v, input)
  1384  		}
  1385  
  1386  		fmt.Fprint(w, `[{"id":1}, {"id":2}]`)
  1387  	})
  1388  
  1389  	ctx := context.Background()
  1390  	deployments, _, err := client.Actions.PendingDeployments(ctx, "o", "r", 399444496, input)
  1391  	if err != nil {
  1392  		t.Errorf("Actions.PendingDeployments returned error: %v", err)
  1393  	}
  1394  
  1395  	want := []*Deployment{{ID: Int64(1)}, {ID: Int64(2)}}
  1396  	if !cmp.Equal(deployments, want) {
  1397  		t.Errorf("Actions.PendingDeployments returned %+v, want %+v", deployments, want)
  1398  	}
  1399  
  1400  	const methodName = "PendingDeployments"
  1401  	testBadOptions(t, methodName, func() (err error) {
  1402  		_, _, err = client.Actions.PendingDeployments(ctx, "\n", "\n", 399444496, input)
  1403  		return err
  1404  	})
  1405  
  1406  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
  1407  		got, resp, err := client.Actions.PendingDeployments(ctx, "o", "r", 399444496, input)
  1408  		if got != nil {
  1409  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
  1410  		}
  1411  		return resp, err
  1412  	})
  1413  }
  1414  
  1415  func TestActionService_GetPendingDeployments(t *testing.T) {
  1416  	t.Parallel()
  1417  	client, mux, _ := setup(t)
  1418  
  1419  	mux.HandleFunc("/repos/o/r/actions/runs/399444496/pending_deployments", func(w http.ResponseWriter, r *http.Request) {
  1420  		testMethod(t, r, "GET")
  1421  		fmt.Fprint(w, `[
  1422  			{
  1423  				"environment": {
  1424  					"id": 1,
  1425  					"node_id": "nid",
  1426  					"name": "n",
  1427  					"url": "u",
  1428  					"html_url": "hu"
  1429  				},
  1430  				"wait_timer": 0,
  1431  				"wait_timer_started_at": `+referenceTimeStr+`,
  1432  				"current_user_can_approve": false,
  1433  				"reviewers": []
  1434  			},
  1435  			{
  1436  				"environment": {
  1437  					"id": 2,
  1438  					"node_id": "nid",
  1439  					"name": "n",
  1440  					"url": "u",
  1441  					"html_url": "hu"
  1442  				},
  1443  				"wait_timer": 13,
  1444  				"wait_timer_started_at": `+referenceTimeStr+`,
  1445  				"current_user_can_approve": true,
  1446  				"reviewers": [
  1447  					{
  1448  						"type": "User",
  1449  						"reviewer": {
  1450  							"login": "l"
  1451  						}
  1452  					},
  1453  					{
  1454  						"type": "Team",
  1455  						"reviewer": {
  1456  							"name": "t",
  1457  							"slug": "s"
  1458  						}
  1459  					}
  1460  				]
  1461  			}
  1462  		]`)
  1463  	})
  1464  
  1465  	ctx := context.Background()
  1466  	deployments, _, err := client.Actions.GetPendingDeployments(ctx, "o", "r", 399444496)
  1467  	if err != nil {
  1468  		t.Errorf("Actions.GetPendingDeployments returned error: %v", err)
  1469  	}
  1470  
  1471  	want := []*PendingDeployment{
  1472  		{
  1473  			Environment: &PendingDeploymentEnvironment{
  1474  				ID:      Int64(1),
  1475  				NodeID:  String("nid"),
  1476  				Name:    String("n"),
  1477  				URL:     String("u"),
  1478  				HTMLURL: String("hu"),
  1479  			},
  1480  			WaitTimer:             Int64(0),
  1481  			WaitTimerStartedAt:    &Timestamp{referenceTime},
  1482  			CurrentUserCanApprove: Bool(false),
  1483  			Reviewers:             []*RequiredReviewer{},
  1484  		},
  1485  		{
  1486  			Environment: &PendingDeploymentEnvironment{
  1487  				ID:      Int64(2),
  1488  				NodeID:  String("nid"),
  1489  				Name:    String("n"),
  1490  				URL:     String("u"),
  1491  				HTMLURL: String("hu"),
  1492  			},
  1493  			WaitTimer:             Int64(13),
  1494  			WaitTimerStartedAt:    &Timestamp{referenceTime},
  1495  			CurrentUserCanApprove: Bool(true),
  1496  			Reviewers: []*RequiredReviewer{
  1497  				{
  1498  					Type: String("User"),
  1499  					Reviewer: &User{
  1500  						Login: String("l"),
  1501  					},
  1502  				},
  1503  				{
  1504  					Type: String("Team"),
  1505  					Reviewer: &Team{
  1506  						Name: String("t"),
  1507  						Slug: String("s"),
  1508  					},
  1509  				},
  1510  			},
  1511  		},
  1512  	}
  1513  
  1514  	if !cmp.Equal(deployments, want) {
  1515  		t.Errorf("Actions.GetPendingDeployments returned %+v, want %+v", deployments, want)
  1516  	}
  1517  
  1518  	const methodName = "GetPendingDeployments"
  1519  	testBadOptions(t, methodName, func() (err error) {
  1520  		_, _, err = client.Actions.GetPendingDeployments(ctx, "\n", "\n", 399444496)
  1521  		return err
  1522  	})
  1523  
  1524  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
  1525  		got, resp, err := client.Actions.GetPendingDeployments(ctx, "o", "r", 399444496)
  1526  		if got != nil {
  1527  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
  1528  		}
  1529  		return resp, err
  1530  	})
  1531  }