Skip to content

Commit

Permalink
More unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
allmightyspiff committed Sep 24, 2024
1 parent 303b98d commit 570631b
Show file tree
Hide file tree
Showing 6 changed files with 153 additions and 16 deletions.
4 changes: 2 additions & 2 deletions .secrets.baseline
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"files": "go.sum|^.secrets.baseline$",
"lines": null
},
"generated_at": "2024-09-20T19:18:35Z",
"generated_at": "2024-09-24T20:48:27Z",
"plugins_used": [
{
"name": "AWSKeyDetector"
Expand Down Expand Up @@ -242,7 +242,7 @@
"hashed_secret": "6f667d3e9627f5549ffeb1055ff294c34430b837",
"is_secret": false,
"is_verified": false,
"line_number": 194,
"line_number": 193,
"type": "Secret Keyword",
"verified_result": null
}
Expand Down
9 changes: 4 additions & 5 deletions examples/cmd/iam_demo.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ package cmd

import (
"fmt"
"time"
"github.com/spf13/cobra"
"time"

"github.com/softlayer/softlayer-go/services"
"github.com/softlayer/softlayer-go/session"
Expand All @@ -26,18 +26,17 @@ func RunIamCmd(cmd *cobra.Command, args []string) error {

// Sets up the session with authentication headers.
sess := &session.Session{
Endpoint: session.DefaultEndpoint,
IAMToken: "Bearer TOKEN",
Endpoint: session.DefaultEndpoint,
IAMToken: "Bearer TOKEN",
IAMRefreshToken: "REFRESH TOKEN",
Debug: true,
Debug: true,
}

// creates a reference to the service object (SoftLayer_Account)
service := services.GetAccountService(sess)

// Sets the mask, filter, result limit, and then makes the API call SoftLayer_Account::getHardware()


for {
account, err := service.Mask(objectMask).GetObject()
if err != nil {
Expand Down
4 changes: 1 addition & 3 deletions session/rest.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ import (

type RestTransport struct{}


// DoRequest - Implementation of the TransportHandler interface for handling
// calls to the REST endpoint.
func (r *RestTransport) DoRequest(sess *Session, service string, method string, args []interface{}, options *sl.Options, pResult interface{}) error {
Expand Down Expand Up @@ -228,6 +227,7 @@ func makeHTTPRequest(
} else {
url = url + session.Endpoint
}
// fmt.Printf("Calling %s/%s", strings.TrimRight(url, "/"), path)
url = fmt.Sprintf("%s/%s", strings.TrimRight(url, "/"), path)
req, err := http.NewRequest(requestType, url, bytes.NewBuffer(requestBody))
if err != nil {
Expand Down Expand Up @@ -348,5 +348,3 @@ func findResponseError(code int, resp []byte) error {
}
return nil
}


62 changes: 60 additions & 2 deletions session/rest_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ package session

import (
"errors"
"testing"

"fmt"
"net/http"
"reflect"
"testing"

"github.com/jarcoal/httpmock"
"github.com/softlayer/softlayer-go/datatypes"
Expand Down Expand Up @@ -320,6 +320,64 @@ func TestRest(t *testing.T) {
}
}

// Tests refreshing a IAM token if it is expired.
func TestRestReauth(t *testing.T) {
// setup session and mock environment
s = New()
s.Endpoint = restEndpoint
s.IAMToken = "Bearer TestToken"
s.IAMRefreshToken = "TestTokenRefresh"
//s.Debug = true
httpmock.Activate()
defer httpmock.DeactivateAndReset()
fmt.Printf("Test [Rest Reauthentication]: ")
slOptions := &sl.Options{}
slResults := &datatypes.Account{}

httpmock.RegisterResponder("GET", fmt.Sprintf("%s/SoftLayer_Account.json", restEndpoint),
func(req *http.Request) (*http.Response, error) {
if s.IAMToken == "Bearer TestToken" {
return httpmock.NewStringResponse(
500,
`{"code":"SoftLayer_Exception_Account_Authentication_AccessTokenValidation", "error": "Expired Token"}`,
), nil
} else {
return httpmock.NewStringResponse(
200,
`{"id":1234,"companyName":"test"}`,
), nil
}
})
httpmock.RegisterResponder("POST", IBMCLOUDIAMENDPOINT,
httpmock.NewStringResponder(200, `{"access_token": "NewToken123", "refresh_token":"NewRefreshToken123", "token_type":"Bearer"}`),
)
err := s.DoRequest("SoftLayer_Account", "getObject", nil, slOptions, slResults)
if err != nil {
t.Errorf("Testing Error: %v\n", err.Error())
}

if s.IAMToken != "Bearer NewToken123" {
t.Errorf("(IAMToken) %s != 'Bearer NewToken123', Refresh Failed.", s.IAMToken)
}
if s.IAMRefreshToken != "NewRefreshToken123" {
t.Errorf("(IAMRefreshToken) %s != 'NewRefreshToken123', Refresh Failed.", s.IAMRefreshToken)
}
if httpmock.GetTotalCallCount() != 3 {
t.Errorf("Call Count = %d, expected 3", httpmock.GetTotalCallCount())
}
callInfo := httpmock.GetCallCountInfo()
fmt.Printf("%v\n", callInfo)
iamUrl := "POST https://iam.cloud.ibm.com/identity/token"
slUrl := "GET https://api.softlayer.com/rest/v3/SoftLayer_Account.json"
if callInfo[iamUrl] != 1 {
t.Errorf("%s called %d times, expected 1", iamUrl, callInfo[iamUrl])
}
if callInfo[slUrl] != 2 {
t.Errorf("%s called %d times, expected 1", slUrl, callInfo[slUrl])
}
teardown()
}

func setup(tc testcase) {
httpmock.RegisterResponder(
httpMethod(tc.method, tc.args),
Expand Down
10 changes: 6 additions & 4 deletions session/session.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@ package session

import (
"context"
"encoding/base64"
"encoding/json"
"fmt"
"io/ioutil"
"log"
"math/rand"
"net"
Expand All @@ -29,10 +32,6 @@ import (
"os/user"
"strings"
"time"
"encoding/base64"
"encoding/json"
"io/ioutil"


"github.com/softlayer/softlayer-go/config"
"github.com/softlayer/softlayer-go/sl"
Expand Down Expand Up @@ -349,6 +348,7 @@ func (r *Session) RefreshToken() error {
reqPayload.Add("refresh_token", r.IAMRefreshToken)

req, err := http.NewRequest("POST", IBMCLOUDIAMENDPOINT, strings.NewReader(reqPayload.Encode()))

if err != nil {
return err
}
Expand All @@ -366,6 +366,7 @@ func (r *Session) RefreshToken() error {
defer resp.Body.Close()

responseBody, err := ioutil.ReadAll(resp.Body)

if err != nil {
return err
}
Expand All @@ -384,6 +385,7 @@ func (r *Session) RefreshToken() error {
if err != nil {
return err
}

r.IAMToken = fmt.Sprintf("%s %s", token.TokenType, token.AccessToken)
r.IAMRefreshToken = token.RefreshToken
return nil
Expand Down
80 changes: 80 additions & 0 deletions session/session_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package session

import (
"fmt"
"github.com/jarcoal/httpmock"
"github.com/softlayer/softlayer-go/sl"
"os"
"strings"
"testing"
Expand Down Expand Up @@ -96,3 +99,80 @@ func TestSetRetries(t *testing.T) {
t.Errorf("Session.Retries (%v) != newVariable (%v)", s.Retries, newVariable)
}
}

func TestNeedsRefresh(t *testing.T) {
testError := sl.Error{
StatusCode: 500,
Exception: "SoftLayer_Exception_Account_Authentication_AccessTokenValidation",
}
if !NeedsRefresh(testError) {
t.Errorf("NeedsRefresh() failed to detect refresh error")
}
testError = sl.Error{
StatusCode: 500,
Exception: "SoftLayer_Exception_Public",
}
if NeedsRefresh(testError) {
t.Errorf("NeedsRefresh() failed to properly error check")
}
}

// Tests refreshing a IAM token if it is expired.
func TestRefreshToken(t *testing.T) {
// setup session and mock environment
s = New()
s.Endpoint = restEndpoint
s.IAMToken = "Bearer TestToken"
s.IAMRefreshToken = "TestTokenRefresh"
//s.Debug = true
httpmock.Activate()
defer httpmock.DeactivateAndReset()
fmt.Printf("TestRefreshToken [Happy Path]: ")
expectedError := ""
// Happy Path
httpmock.RegisterResponder("POST", IBMCLOUDIAMENDPOINT,
httpmock.NewStringResponder(200, `{"access_token": "NewToken123", "refresh_token":"NewRefreshToken123", "token_type":"Bearer"}`),
)
err := s.RefreshToken()
if err != nil {
t.Errorf("Testing Error: %v\n", err.Error())
}

if s.IAMToken != "Bearer NewToken123" {
t.Errorf("(IAMToken) %s != 'Bearer NewToken123', Refresh Failed.", s.IAMToken)
}
if s.IAMRefreshToken != "NewRefreshToken123" {
t.Errorf("(IAMRefreshToken) %s != 'NewRefreshToken123', Refresh Failed.", s.IAMRefreshToken)
}
httpmock.Reset()

// Error returned from IAM API
fmt.Printf("TestRefreshToken [API error]: ")
httpmock.RegisterResponder("POST", IBMCLOUDIAMENDPOINT,
httpmock.NewStringResponder(400, `{"errormessage": "Some Error", "errorcode":"400"}`),
)
err = s.RefreshToken()
if err == nil {
t.Errorf("Expected an error, none returned\n")
}
expectedError = "400: Some Error "
if err.Error() != expectedError {
t.Errorf("Expected |%s| == %s", err.Error(), expectedError)
}
httpmock.Reset()

// Junk returned from IAM API
fmt.Printf("TestRefreshToken [Bad Response]: ")
httpmock.RegisterResponder("POST", IBMCLOUDIAMENDPOINT,
httpmock.NewStringResponder(200, ""),
)
err = s.RefreshToken()
if err == nil {
t.Errorf("Expected an error, none returned\n")
}
expectedError = "unexpected end of JSON input"
if err.Error() != expectedError {
t.Errorf("Expected %s == %s", err.Error(), expectedError)
}
httpmock.Reset()
}

0 comments on commit 570631b

Please sign in to comment.