From 3bc7983cec34ba37a6b0ca92ac9c823b757cb378 Mon Sep 17 00:00:00 2001 From: Yashk767 <76935991+Yashk767@users.noreply.github.com> Date: Thu, 2 Feb 2023 16:20:10 +0530 Subject: [PATCH] Fetched API key from env file (#1048) * Added dot env file utils * Fetched API key from .env file when required * updated dependencies * Changed API key regex * Added name field in customJob struct * Replaced content-type field with headers in dataSourceURLStruct * Updated post request creation * picked API Regex from constants.go * Removed unwanted field from header * returned error as well from GetkeywordAndAPIKey * replaces regexp.Match() with strings.Contains() * support for headers in GET requests * Refactored GetDataFromAPI * Added processRequest retry constants --- README.md | 4 ++ core/constants.go | 9 ++++ core/types/assets.go | 9 ++-- go.mod | 1 + go.sum | 2 + path/mocks/path_interface.go | 21 ++++++++ path/path.go | 10 ++++ path/pathUtils.go | 1 + utils/api.go | 96 ++++++++++++++++++++++++------------ utils/api_test.go | 68 ++++++++----------------- utils/asset.go | 54 ++++++++++++++++++-- utils/asset_test.go | 31 +++++++++--- 12 files changed, 212 insertions(+), 94 deletions(-) diff --git a/README.md b/README.md index 0e717f73..690c4fc3 100644 --- a/README.md +++ b/README.md @@ -873,6 +873,10 @@ Shown below is an example of how your `assets.json` file should be - "body": {}, "content-type": "" }, + "name:" "eth_lunarCrush", + "selector": "[`data`][`0`][`price`]", + "power": 3, + "weight": 2 ] } } diff --git a/core/constants.go b/core/constants.go index 794c4ea7..9a912680 100644 --- a/core/constants.go +++ b/core/constants.go @@ -47,6 +47,15 @@ var AssetsDataFile = "assets.json" var ConfigFile = "razor.yaml" var LogFileDirectory = "logs" var DefaultPathName = ".razor" +var DotENVFileName = ".env" //BlockNumberInterval is the interval in seconds after which blockNumber needs to be calculated again var BlockNumberInterval = 5 + +//APIKeyRegex will be used as a regular expression to be matched in job Urls +var APIKeyRegex = `$` + +// Following are the constants which defines retry attempts and retry delay if there is an error in processing request + +var ProcessRequestRetryAttempts uint = 2 +var ProcessRequestRetryDelay = 2 diff --git a/core/types/assets.go b/core/types/assets.go index 4b4cb15d..0668a318 100644 --- a/core/types/assets.go +++ b/core/types/assets.go @@ -51,14 +51,15 @@ type AssignedAsset struct { type CustomJob struct { URL string `json:"URL"` + Name string `json:"name"` Selector string `json:"selector"` Power int8 `json:"power"` Weight uint8 `json:"weight"` } type DataSourceURL struct { - Type string `json:"type"` - URL string `json:"url"` - Body map[string]interface{} `json:"body"` - ContentType string `json:"content-type"` + Type string `json:"type"` + URL string `json:"url"` + Body map[string]interface{} `json:"body"` + Header map[string]string `json:"header"` } diff --git a/go.mod b/go.mod index b598d3b0..b84f2561 100644 --- a/go.mod +++ b/go.mod @@ -49,6 +49,7 @@ require ( github.com/gorilla/websocket v1.4.2 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/inconshreveable/mousetrap v1.0.0 // indirect + github.com/joho/godotenv v1.4.0 // indirect github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a // indirect github.com/kennygrant/sanitize v1.2.4 // indirect github.com/lunixbochs/vtclean v0.0.0-20180621232353-2d01aacdc34a // indirect diff --git a/go.sum b/go.sum index c2c95589..b81af828 100644 --- a/go.sum +++ b/go.sum @@ -344,6 +344,8 @@ github.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e/go.mod h1:G1C github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= +github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg= +github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= diff --git a/path/mocks/path_interface.go b/path/mocks/path_interface.go index 7d411dc5..a931e91e 100644 --- a/path/mocks/path_interface.go +++ b/path/mocks/path_interface.go @@ -93,6 +93,27 @@ func (_m *PathInterface) GetDisputeDataFileName(address string) (string, error) return r0, r1 } +// GetDotENVFilePath provides a mock function with given fields: +func (_m *PathInterface) GetDotENVFilePath() (string, error) { + ret := _m.Called() + + var r0 string + if rf, ok := ret.Get(0).(func() string); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(string) + } + + var r1 error + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // GetJobFilePath provides a mock function with given fields: func (_m *PathInterface) GetJobFilePath() (string, error) { ret := _m.Called() diff --git a/path/path.go b/path/path.go index 259bf83b..9d225456 100644 --- a/path/path.go +++ b/path/path.go @@ -113,3 +113,13 @@ func (PathUtils) GetDisputeDataFileName(address string) (string, error) { } return filepath.Join(dataFileDir, address+core.DisputeDataFile), nil } + +//This function returns the job file path +func (PathUtils) GetDotENVFilePath() (string, error) { + razorPath, err := PathUtilsInterface.GetDefaultPath() + if err != nil { + return "", err + } + filePath := filepath.Join(razorPath, core.DotENVFileName) + return filePath, nil +} diff --git a/path/pathUtils.go b/path/pathUtils.go index 667f1c35..51bc8c39 100644 --- a/path/pathUtils.go +++ b/path/pathUtils.go @@ -20,6 +20,7 @@ type PathInterface interface { GetCommitDataFileName(address string) (string, error) GetProposeDataFileName(address string) (string, error) GetDisputeDataFileName(address string) (string, error) + GetDotENVFilePath() (string, error) } type OSInterface interface { diff --git a/utils/api.go b/utils/api.go index e36607dc..ad0b2427 100644 --- a/utils/api.go +++ b/utils/api.go @@ -4,12 +4,13 @@ import ( "bytes" "encoding/json" "errors" + "io" "net/http" "razor/cache" "razor/core" + "strings" "time" - "io/ioutil" "razor/core/types" "github.com/PaesslerAG/jsonpath" @@ -23,62 +24,51 @@ func (*UtilsStruct) GetDataFromAPI(dataSourceURLStruct types.DataSourceURL, loca } cachedData, cachedErr := localCache.Read(dataSourceURLStruct.URL) if cachedErr != nil { - var body []byte - if dataSourceURLStruct.Type == "GET" { + var response []byte + switch dataSourceURLStruct.Type { + case "GET": err := retry.Do( func() error { - response, err := client.Get(dataSourceURLStruct.URL) - if err != nil { - return err - } - defer response.Body.Close() - if response.StatusCode != 200 { - log.Errorf("API: %s responded with status code %d", dataSourceURLStruct.URL, response.StatusCode) - return errors.New("unable to reach API") - } - body, err = IOInterface.ReadAll(response.Body) + responseBody, err := ProcessRequest(client, dataSourceURLStruct, nil) if err != nil { + log.Error("Error in processing GET request: ", err) return err } + response = responseBody return nil - }, retry.Attempts(2), retry.Delay(time.Second*2)) + }, retry.Attempts(core.ProcessRequestRetryAttempts), retry.Delay(time.Second*time.Duration(core.ProcessRequestRetryDelay))) if err != nil { return nil, err } - } - if dataSourceURLStruct.Type == "POST" { + case "POST": postBody, err := json.Marshal(dataSourceURLStruct.Body) if err != nil { log.Errorf("Error in marshalling body of a POST request URL %s: %v", dataSourceURLStruct.URL, err) + return nil, err } - responseBody := bytes.NewBuffer(postBody) + requestBody := bytes.NewBuffer(postBody) err = retry.Do( func() error { - response, err := client.Post(dataSourceURLStruct.URL, dataSourceURLStruct.ContentType, responseBody) - if err != nil { - log.Errorf("Error sending POST request URL %s: %v", dataSourceURLStruct.URL, err) - return err - } - defer response.Body.Close() - if response.StatusCode != 200 { - log.Errorf("URL: %s responded with status code %d", dataSourceURLStruct.URL, response.StatusCode) - return errors.New("unable to reach API") - } - body, err = ioutil.ReadAll(response.Body) + responseBody, err := ProcessRequest(client, dataSourceURLStruct, requestBody) if err != nil { + log.Error("Error in processing POST request: ", err) return err } + response = responseBody return nil - }, retry.Attempts(2), retry.Delay(time.Second*2)) + }, retry.Attempts(core.ProcessRequestRetryAttempts), retry.Delay(time.Second*time.Duration(core.ProcessRequestRetryDelay))) if err != nil { return nil, err } + default: + return nil, errors.New("invalid request type") } + dataToCache := cache.Data{ - Result: body, + Result: response, } localCache.Update(dataToCache, dataSourceURLStruct.URL, time.Now().Add(time.Second*time.Duration(core.StateLength)).Unix()) - return body, nil + return response, nil } log.Debugf("Getting Data for URL %s from local cache...", dataSourceURLStruct.URL) return cachedData.Result, nil @@ -105,3 +95,47 @@ func (*UtilsStruct) GetDataFromXHTML(dataSourceURLStruct types.DataSourceURL, se } return priceData, nil } + +func AddHeaderToRequest(request *http.Request, headerMap map[string]string) (*http.Request, error) { + for key, value := range headerMap { + // If core.APIKeyRegex = `$` and if value starts with '$' then we need to fetch the respective value from env file + if strings.HasPrefix(value, core.APIKeyRegex) { + _, APIKey, err := GetKeyWordAndAPIKeyFromENVFile(value) + if err != nil { + log.Error("Error in getting value from env file: ", err) + return nil, err + } + value = APIKey + } + log.Debugf("Adding key: %s, value: %s pair to header", key, value) + request.Header.Add(key, value) + } + return request, nil +} + +func ProcessRequest(client http.Client, dataSourceURLStruct types.DataSourceURL, requestBody io.Reader) ([]byte, error) { + request, err := http.NewRequest(dataSourceURLStruct.Type, dataSourceURLStruct.URL, requestBody) + if err != nil { + return nil, err + } + requestWithHeader, err := AddHeaderToRequest(request, dataSourceURLStruct.Header) + if err != nil { + log.Errorf("Error in adding header to %s request: %v", dataSourceURLStruct.Type, err) + return nil, err + } + response, err := client.Do(requestWithHeader) + if err != nil { + log.Errorf("Error sending %s request URL %s: %v", dataSourceURLStruct.Type, dataSourceURLStruct.URL, err) + return nil, err + } + defer response.Body.Close() + if response.StatusCode != 200 { + log.Errorf("API: %s responded with status code %d", dataSourceURLStruct.URL, response.StatusCode) + return nil, errors.New("unable to reach API") + } + responseBody, err := io.ReadAll(response.Body) + if err != nil { + return nil, err + } + return responseBody, nil +} diff --git a/utils/api_test.go b/utils/api_test.go index c22e5785..ebff1667 100644 --- a/utils/api_test.go +++ b/utils/api_test.go @@ -2,16 +2,12 @@ package utils import ( "encoding/hex" - "errors" - "fmt" "razor/cache" "razor/core/types" "razor/utils/mocks" "reflect" "testing" "time" - - "github.com/stretchr/testify/mock" ) func getAPIByteArray(index int) []byte { @@ -34,13 +30,11 @@ func getAPIByteArray(index int) []byte { } func TestGetDataFromAPI(t *testing.T) { - //postRequestInput := `{"type": "POST","url": "https://staging-v3.skalenodes.com/v1/staging-aware-chief-gianfar","body": {"jsonrpc": "2.0","method": "eth_chainId","params": [],"id": 0},"content-type": "application/json"}` + //postRequestInput := `{"type": "POST","url": "https://staging-v3.skalenodes.com/v1/staging-aware-chief-gianfar","body": {"jsonrpc": "2.0","method": "eth_chainId","params": [],"id": 0},"header": {"content-type": "application/json"}}` sampleChainId, _ := hex.DecodeString("7b226964223a302c226a736f6e727063223a22322e30222c22726573756c74223a2230783561373963343465227d") type args struct { urlStruct types.DataSourceURL - body []byte - bodyErr error } tests := []struct { name string @@ -52,12 +46,11 @@ func TestGetDataFromAPI(t *testing.T) { name: "TODO API", args: args{ urlStruct: types.DataSourceURL{ - Type: "GET", - URL: "https://jsonplaceholder.typicode.com/todos/1", - Body: nil, - ContentType: "", + Type: "GET", + URL: "https://jsonplaceholder.typicode.com/todos/1", + Body: nil, + Header: nil, }, - body: getAPIByteArray(0), }, want: getAPIByteArray(0), wantErr: false, @@ -66,11 +59,10 @@ func TestGetDataFromAPI(t *testing.T) { name: "Comments API", args: args{ urlStruct: types.DataSourceURL{Type: "GET", - URL: "https://jsonplaceholder.typicode.com/comments/1", - Body: nil, - ContentType: "", + URL: "https://jsonplaceholder.typicode.com/comments/1", + Body: nil, + Header: nil, }, - body: getAPIByteArray(1), }, want: getAPIByteArray(1), wantErr: false, @@ -79,12 +71,11 @@ func TestGetDataFromAPI(t *testing.T) { name: "When API is invalid", args: args{ urlStruct: types.DataSourceURL{ - Type: "GET", - URL: "https:api.gemini.com/v1/pubticker", - Body: nil, - ContentType: "", + Type: "GET", + URL: "https:api.gemini.com/v1/pubticker", + Body: nil, + Header: nil, }, - body: getAPIByteArray(0), }, want: nil, wantErr: true, @@ -93,26 +84,11 @@ func TestGetDataFromAPI(t *testing.T) { name: "When API is not responding", args: args{ urlStruct: types.DataSourceURL{ - Type: "GET", - URL: "https://api.gemini.com/v1/pubticker/TEST", - Body: nil, - ContentType: "", - }, - body: getAPIByteArray(0), - }, - want: nil, - wantErr: true, - }, - { - name: "When there is an error in getting body", - args: args{ - urlStruct: types.DataSourceURL{ - Type: "GET", - URL: "https://jsonplaceholder.typicode.com/todos/1", - Body: nil, - ContentType: "", + Type: "GET", + URL: "https://api.gemini.com/v1/pubticker/TEST", + Body: nil, + Header: nil, }, - bodyErr: errors.New("body error"), }, want: nil, wantErr: true, @@ -121,10 +97,10 @@ func TestGetDataFromAPI(t *testing.T) { name: "Post request to fetch chainId", args: args{ urlStruct: types.DataSourceURL{ - Type: "POST", - URL: "https://staging-v3.skalenodes.com/v1/staging-aware-chief-gianfar", - Body: map[string]interface{}{"jsonrpc": "2.0", "method": "eth_chainId", "params": nil, "id": 0}, - ContentType: "application/json", + Type: "POST", + URL: "https://staging-v3.skalenodes.com/v1/staging-aware-chief-gianfar", + Body: map[string]interface{}{"jsonrpc": "2.0", "method": "eth_chainId", "params": nil, "id": 0}, + Header: map[string]string{"content-type": "application/json"}, }, }, want: sampleChainId, @@ -133,18 +109,14 @@ func TestGetDataFromAPI(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { utilsMock := new(mocks.Utils) - ioMock := new(mocks.IOUtils) optionsPackageStruct := OptionsPackageStruct{ UtilsInterface: utilsMock, - IOInterface: ioMock, } utils := StartRazor(optionsPackageStruct) - ioMock.On("ReadAll", mock.Anything).Return(tt.args.body, tt.args.bodyErr) localCache := cache.NewLocalCache(time.Second * 10) got, err := utils.GetDataFromAPI(tt.args.urlStruct, localCache) - fmt.Println("ABC: ", hex.EncodeToString(got)) if (err != nil) != tt.wantErr { t.Errorf("GetDataFromAPI() error = %v, wantErr %v", err, tt.wantErr) return diff --git a/utils/asset.go b/utils/asset.go index f3597e47..fee272ca 100644 --- a/utils/asset.go +++ b/utils/asset.go @@ -19,6 +19,7 @@ import ( "github.com/avast/retry-go" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/ethclient" + "github.com/joho/godotenv" "github.com/tidwall/gjson" solsha3 "github.com/miguelmota/go-solidity-sha3" @@ -292,11 +293,25 @@ func (*UtilsStruct) GetDataToCommitFromJob(job bindings.StructsJob, localCache * log.Infof("URL Struct: %+v", dataSourceURLStruct) } else { log.Debug("Job URL passed is a direct URL: ", job.Url) + isAPIKeyRequired := strings.Contains(job.Url, core.APIKeyRegex) + if isAPIKeyRequired { + keyword, APIKey, err := GetKeyWordAndAPIKeyFromENVFile(job.Url) + if err != nil { + log.Error("Error in getting value from env file: ", err) + return nil, err + } + log.Debug("API key: ", APIKey) + keywordWithAPIKeyRegex := core.APIKeyRegex + keyword + log.Debug("Keyword to replace in url: ", keywordWithAPIKeyRegex) + urlWithAPIKey := strings.Replace(job.Url, keywordWithAPIKeyRegex, APIKey, 1) + log.Debug("URl with API key: ", urlWithAPIKey) + job.Url = urlWithAPIKey + } dataSourceURLStruct = types.DataSourceURL{ - URL: job.Url, - Type: "GET", - Body: nil, - ContentType: "", + URL: job.Url, + Type: "GET", + Body: nil, + Header: nil, } } // Fetch data from API with retry mechanism @@ -434,6 +449,10 @@ func GetCustomJobsFromJSONFile(collection string, jsonFileData string) []binding if url.Exists() { customJob.URL = url.String() } + name := gjson.Get(customJobsData, "name") + if name.Exists() { + customJob.Name = name.String() + } selector := gjson.Get(customJobsData, "selector") if selector.Exists() { customJob.Selector = selector.String() @@ -457,6 +476,7 @@ func GetCustomJobsFromJSONFile(collection string, jsonFileData string) []binding func ConvertCustomJobToStructJob(customJob types.CustomJob) bindings.StructsJob { return bindings.StructsJob{ Url: customJob.URL, + Name: customJob.Name, Selector: customJob.Selector, Power: customJob.Power, Weight: customJob.Weight, @@ -507,3 +527,29 @@ func (*UtilsStruct) HandleOfficialJobsFromJSONFile(client *ethclient.Client, col return overrideJobs, overriddenJobIds } + +func GetKeyWordAndAPIKeyFromENVFile(url string) (string, string, error) { + envFilePath, err := path.PathUtilsInterface.GetDotENVFilePath() + if err != nil { + log.Error("Error in getting env file path: ", err) + return "", "", err + } + log.Debug("GetKeyWordAndAPIKeyFromENVFile: .env file path: ", envFilePath) + + log.Info("Loading env file...") + envFileMap, err := godotenv.Read(envFilePath) + if err != nil { + log.Error("Error in getting env file map: ", err) + return "", "", err + } + log.Debugf("GetKeyWordAndAPIKeyFromENVFile: ENV file map: %v", envFileMap) + for keyword, APIKey := range envFileMap { + keywordWithAPIKeyRegex := core.APIKeyRegex + keyword + isTheKeywordPresentInURL := strings.Contains(url, keywordWithAPIKeyRegex) + if isTheKeywordPresentInURL { + log.Infof("Found the keyword %s in env file", keyword) + return keyword, APIKey, nil + } + } + return "", "", errors.New("no value found in env file") +} diff --git a/utils/asset_test.go b/utils/asset_test.go index ab5d332a..19fcd1ec 100644 --- a/utils/asset_test.go +++ b/utils/asset_test.go @@ -552,10 +552,10 @@ func TestGetDataToCommitFromJobs(t *testing.T) { jobsArray := []bindings.StructsJob{ {Id: 1, SelectorType: 1, Weight: 100, Power: 2, Name: "ethusd_gemini", Selector: "last", - Url: `{"type": "GET","url": "https://api.gemini.com/v1/pubticker/ethusd","body": {},"content-type": ""}`, + Url: `{"type": "GET","url": "https://api.gemini.com/v1/pubticker/ethusd","body": {},"header": {}}`, }, {Id: 2, SelectorType: 1, Weight: 100, Power: 2, Name: "ethusd_gemini", Selector: "last", - Url: `{"type": "GET","url": "https://api.gemini.com/v1/pubticker/ethusd","body": {},"content-type": ""}`, + Url: `{"type": "GET","url": "https://api.gemini.com/v1/pubticker/ethusd","body": {},"header": {}}`, }, } @@ -580,7 +580,7 @@ func TestGetDataToCommitFromJobs(t *testing.T) { overrideJobData: map[string]*types.StructsJob{"1": { Id: 2, SelectorType: 1, Weight: 100, Power: 2, Name: "ethusd_gemini", Selector: "last", - Url: `{"type": "GET","url": "https://api.gemini.com/v1/pubticker/ethusd","body": {},"content-type": ""}`, + Url: `{"type": "GET","url": "https://api.gemini.com/v1/pubticker/ethusd","body": {},"header": {}}`, }}, dataToAppend: big.NewInt(1), }, @@ -629,8 +629,6 @@ func TestGetDataToCommitFromJobs(t *testing.T) { } utils := StartRazor(optionsPackageStruct) - pathMock.On("GetJobFilePath").Return(tt.args.jobPath, tt.args.jobPathErr) - utilsMock.On("ReadJSONData", mock.AnythingOfType("string")).Return(tt.args.overrideJobData, tt.args.overrideJobDataErr) utilsMock.On("GetDataToCommitFromJob", mock.Anything, mock.Anything).Return(tt.args.dataToAppend, tt.args.dataToAppendErr) got, _, err := utils.GetDataToCommitFromJobs(jobsArray, &cache.LocalCache{}) @@ -648,12 +646,17 @@ func TestGetDataToCommitFromJobs(t *testing.T) { func TestGetDataToCommitFromJob(t *testing.T) { job := bindings.StructsJob{Id: 1, SelectorType: 1, Weight: 100, Power: 2, Name: "ethusd_gemini", Selector: "last", - Url: `{"type": "GET","url": "https://api.gemini.com/v1/pubticker/ethusd","body": {},"content-type": ""}`, + Url: `{"type": "GET","url": "https://api.gemini.com/v1/pubticker/ethusd","body": {},"header": {}}`, } job2 := bindings.StructsJob{Id: 1, SelectorType: 0, Weight: 100, Power: 2, Name: "ethusd_gemini", Selector: "last", - Url: `{"type": "GET","url": "https://api.gemini.com/v1/pubticker/ethusd","body": {},"content-type": ""}`, + Url: `{"type": "GET","url": "https://api.gemini.com/v1/pubticker/ethusd","body": {},"header": {}}`, + } + + job3 := bindings.StructsJob{Id: 1, SelectorType: 0, Weight: 100, + Power: 2, Name: "ethusd_sample", Selector: "last", + Url: "https://api.gemini.com/v1/pubticker/ethusd/apiKey=$ethusd_sample_key", } response := []byte(`{ @@ -776,6 +779,14 @@ func TestGetDataToCommitFromJob(t *testing.T) { want: nil, wantErr: true, }, + { + name: "Test 9: When there is a case to pick up API key from .env file and env file is not present", + args: args{ + job: job3, + }, + want: nil, + wantErr: true, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -786,10 +797,14 @@ func TestGetDataToCommitFromJob(t *testing.T) { } utils := StartRazor(optionsPackageStruct) + pathUtilsMock := new(pathMocks.PathInterface) + path.PathUtilsInterface = pathUtilsMock + utilsMock.On("GetDataFromAPI", mock.Anything, mock.Anything).Return(tt.args.response, tt.args.responseErr) utilsMock.On("GetDataFromJSON", mock.Anything, mock.AnythingOfType("string")).Return(tt.args.parsedData, tt.args.parsedDataErr) utilsMock.On("GetDataFromXHTML", mock.Anything, mock.AnythingOfType("string")).Return(tt.args.dataPoint, tt.args.dataPointErr) utilsMock.On("ConvertToNumber", mock.Anything).Return(tt.args.datum, tt.args.datumErr) + pathUtilsMock.On("GetDotENVFilePath", mock.Anything).Return("$HOME/.razor/.env", nil) got, err := utils.GetDataToCommitFromJob(tt.args.job, &cache.LocalCache{}) if (err != nil) != tt.wantErr { @@ -1093,12 +1108,14 @@ func TestConvertCustomJobToStructJob(t *testing.T) { args: args{ customJob: types.CustomJob{ URL: "http://api.coinbase.com/eth2", + Name: "eth_coinBase", Power: 3, Weight: 2, }, }, want: bindings.StructsJob{ Url: "http://api.coinbase.com/eth2", + Name: "eth_coinBase", Power: 3, Weight: 2, },