[ISSUE-67869881] add more test cases
diff --git a/common/cipher.go b/common/cipher.go index 5e727a2..9235937 100644 --- a/common/cipher.go +++ b/common/cipher.go
@@ -74,7 +74,7 @@ } func (c *KmsCipherManager) startRetrieve(org string, interval time.Duration, timeout time.Duration) { - + timeoutChan := time.After(timeout) if err := c.retrieveKey(org); err != nil { log.Error(err) } else { @@ -83,7 +83,7 @@ ticker := time.NewTicker(interval) for { select { - case <-time.After(timeout): + case <-timeoutChan: log.Error("timeout when retrieving key") return case <-ticker.C: @@ -116,7 +116,7 @@ if res.StatusCode == http.StatusNotFound { e, err := parseErrorResponse(res) if err != nil { - log.Errorf("Failed to parse error response: %v", err) + log.Errorf("Failed to parse 404 error response for org %s: %v", org, err) return err } // is this org has no key, stop retrying @@ -251,8 +251,8 @@ } type KeyErrorResponse struct { - Code string - Message string + Code string `json:"code"` + Message string `json:"message"` } func parseErrorResponse(res *http.Response) (*KeyErrorResponse, error) {
diff --git a/common/cipher_test.go b/common/cipher_test.go index 62162ad..71ff7d4 100644 --- a/common/cipher_test.go +++ b/common/cipher_test.go
@@ -15,6 +15,8 @@ import ( "encoding/base64" + "encoding/json" + "encoding/xml" "fmt" "github.com/apid/apid-core/cipher" . "github.com/onsi/ginkgo" @@ -61,47 +63,155 @@ Context("Retrieve new key", func() { var server *httptest.Server - BeforeEach(func() { - // set key server - server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - defer GinkgoRecover() - Expect(r.URL.Path).Should(Equal(retrieveEncryptKeyPath)) - Expect(r.URL.Query().Get(parameterOrganization)).Should(Equal(testOrg)) - Expect(w.Write([]byte(base64.StdEncoding.EncodeToString(key)))).Should(Equal(24)) - })) - time.Sleep(100 * time.Millisecond) - testCipherMan = CreateCipherManager(&http.Client{}, server.URL) - }) - - AfterEach(func() { - server.Close() - }) - - It("Encryption", func() { - Expect(testCipherMan.EncryptBase64(plaingtext, testOrg, cipher.ModeEcb, cipher.PaddingPKCS5)). - Should(Equal(cipher64)) - }) - - It("Decryption", func() { - Expect(testCipherMan.TryDecryptBase64(cipher64, testOrg)).Should(Equal(plaingtext)) - }) - - It("Retrieve Key", func() { - testCipherMan.AddOrgs([]string{testOrg}) - for { + Context("Retrieve new key with lazy method", func() { + BeforeEach(func() { + // set key server + server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + defer GinkgoRecover() + Expect(r.URL.Path).Should(Equal(retrieveEncryptKeyPath)) + Expect(r.URL.Query().Get(parameterOrganization)).Should(Equal(testOrg)) + Expect(w.Write([]byte(base64.StdEncoding.EncodeToString(key)))).Should(Equal(24)) + })) time.Sleep(100 * time.Millisecond) - testCipherMan.mutex.RLock() - aesCipher := testCipherMan.aes[testOrg] - testCipherMan.mutex.RUnlock() - if aesCipher != nil { - //close server to make sure key was retrieved by "AddOrgs" - server.Close() - Expect(testCipherMan.EncryptBase64(plaingtext, testOrg, cipher.ModeEcb, cipher.PaddingPKCS5)). - Should(Equal(cipher64)) - return + testCipherMan = CreateCipherManager(&http.Client{}, server.URL) + }) + + AfterEach(func() { + server.Close() + }) + + It("Encryption", func() { + Expect(testCipherMan.EncryptBase64(plaingtext, testOrg, cipher.ModeEcb, cipher.PaddingPKCS5)). + Should(Equal(cipher64)) + }) + + It("Decryption", func() { + Expect(testCipherMan.TryDecryptBase64(cipher64, testOrg)).Should(Equal(plaingtext)) + }) + }) + + Context("Retrieve new keys during initialization", func() { + + AfterEach(func() { + server.Close() + }) + + It("Retrieve Key happy path", func() { + // set key server + server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + defer GinkgoRecover() + Expect(r.URL.Path).Should(Equal(retrieveEncryptKeyPath)) + Expect(r.URL.Query().Get(parameterOrganization)).Should(HavePrefix(testOrg)) + Expect(w.Write([]byte(base64.StdEncoding.EncodeToString(key)))).Should(Equal(24)) + })) + time.Sleep(100 * time.Millisecond) + testCipherMan = CreateCipherManager(&http.Client{}, server.URL) + + //test 2 orgs + testOrg1 := testOrg + "_1" + testCipherMan.AddOrgs([]string{testOrg, testOrg1}) + for { + time.Sleep(100 * time.Millisecond) + testCipherMan.mutex.RLock() + l := len(testCipherMan.aes) + testCipherMan.mutex.RUnlock() + if l == 2 { + //close server to make sure key was retrieved by "AddOrgs" + server.Close() + Expect(testCipherMan.EncryptBase64(plaingtext, testOrg, cipher.ModeEcb, cipher.PaddingPKCS5)). + Should(Equal(cipher64)) + Expect(testCipherMan.EncryptBase64(plaingtext, testOrg1, cipher.ModeEcb, cipher.PaddingPKCS5)). + Should(Equal(cipher64)) + return + } } - } - }, 2) + }, 2) + + It("Retrieve Key should retry for internal server error", func() { + // set key server + count := 0 + server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + defer GinkgoRecover() + Expect(r.URL.Path).Should(Equal(retrieveEncryptKeyPath)) + Expect(r.URL.Query().Get(parameterOrganization)).Should(Equal(testOrg)) + count++ + if count == 1 { + w.WriteHeader(http.StatusInternalServerError) + return + } + if count == 2 { + w.WriteHeader(http.StatusNotFound) + return + } + Expect(w.Write([]byte(base64.StdEncoding.EncodeToString(key)))).Should(Equal(24)) + })) + time.Sleep(100 * time.Millisecond) + testCipherMan = CreateCipherManager(&http.Client{}, server.URL) + testCipherMan.interval = 100 * time.Millisecond + //should retry in case of error + testCipherMan.AddOrgs([]string{testOrg}) + for { + time.Sleep(100 * time.Millisecond) + testCipherMan.mutex.RLock() + aes := testCipherMan.aes[testOrg] + testCipherMan.mutex.RUnlock() + if aes != nil { + //close server to make sure key was retrieved by "AddOrgs" + server.Close() + Expect(testCipherMan.EncryptBase64(plaingtext, testOrg, cipher.ModeEcb, cipher.PaddingPKCS5)). + Should(Equal(cipher64)) + return + } + } + }, 2) + + It("Retrieve Key should stop retrying for JSON organizations.EncryptionKeyDoesNotExist", func() { + // set key server + server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + defer GinkgoRecover() + Expect(r.URL.Path).Should(Equal(retrieveEncryptKeyPath)) + Expect(r.URL.Query().Get(parameterOrganization)).Should(Equal(testOrg)) + + response := KeyErrorResponse{ + Code: errorCodeNoKey, + Message: fmt.Sprintf("Encryption key does not exist for the org [%s].", testOrg), + } + bytes, err := json.Marshal(response) + Expect(err).Should(Succeed()) + w.Header().Set(headerContentType, typeJson) + w.WriteHeader(http.StatusNotFound) + Expect(w.Write(bytes)).Should(Equal(len(bytes))) + })) + time.Sleep(100 * time.Millisecond) + testCipherMan = CreateCipherManager(&http.Client{}, server.URL) + //should stop retrying after one try + testCipherMan.startRetrieve(testOrg, 100*time.Millisecond, 10*time.Minute) + }, 2) + + It("Retrieve Key should stop retrying for XML organizations.EncryptionKeyDoesNotExist", func() { + // set key server + server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + defer GinkgoRecover() + Expect(r.URL.Path).Should(Equal(retrieveEncryptKeyPath)) + Expect(r.URL.Query().Get(parameterOrganization)).Should(Equal(testOrg)) + + response := KeyErrorResponse{ + Code: errorCodeNoKey, + Message: fmt.Sprintf("Encryption key does not exist for the org [%s].", testOrg), + } + bytes, err := xml.Marshal(response) + Expect(err).Should(Succeed()) + w.Header().Set(headerContentType, typeXml) + w.WriteHeader(http.StatusNotFound) + Expect(w.Write(bytes)).Should(Equal(len(bytes))) + })) + time.Sleep(100 * time.Millisecond) + testCipherMan = CreateCipherManager(&http.Client{}, server.URL) + //should stop retrying after one try + testCipherMan.startRetrieve(testOrg, 100*time.Millisecond, 10*time.Minute) + }, 2) + }) + }) Context("IsEncrypted", func() {