package secret import ( "bytes" "context" "errors" "fmt" "os" "testing" "time" ) type mockProvider struct { out []byte err error } func (p mockProvider) GetSecret(_ string) ([]byte, error) { return p.out, p.err } type testProviderCase struct { Name string Key string Err error Test func([]byte) error } func testProvider(t *testing.T, p Provider, tests ...testProviderCase) { t.Helper() for _, test := range tests { if test.Name == "" { test.Name = test.Key } t.Run(test.Name, func(it *testing.T) { v, err := p.GetSecret(test.Key) if err != nil { if test.Err == nil { it.Fatalf("unexpected error %q in %T (%#+v)", err, p, p) return } else if !errors.Is(err, test.Err) { it.Fatalf("unexpected error %q, expected error %q", err, test.Err) return } return } else if test.Err != nil { it.Fatalf("expected error %q", test.Err) return } if err := test.Test(v); err != nil { it.Error(err) } }) } } func testCrypter(t *testing.T, p Provider, keyID string) { t.Helper() ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) defer cancel() vector := []byte("Hello, Gophers! ʕ◔ϖ◔ʔ") ciphertext, err := Encrypt(ctx, p, keyID, vector) if err != nil { t.Error(err) return } plaintext, err := Decrypt(ctx, p, keyID, ciphertext) if err != nil { t.Error(err) return } if err = testEqual(vector)(plaintext); err != nil { t.Error(err) } } func testNotEmpty(v []byte) error { if len(v) > 0 { return nil } return fmt.Errorf("expected empty, got %q", v) } func testEqual(a []byte) func([]byte) error { return func(b []byte) error { if bytes.Equal(a, b) { return nil } return fmt.Errorf("expected %q, got %q", a, b) } } func testEqualString(a string) func([]byte) error { return testEqual([]byte(a)) } func testInPipeline() (string, bool) { if os.Getenv("CI") != "" { switch { case os.Getenv("GITEA_ACTIONS") != "": return "gitea", true case os.Getenv("GITHUB_ACTIONS") != "": return "github", true case os.Getenv("CI_RUNNER_ID") != "": return "gitlab", true } } return "", true }