You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

229 lines
5.9 KiB

  1. // Copyright 2016 Google LLC
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. // TODO(jba): document in CONTRIBUTING.md that service account must be given "Logs Configuration Writer" IAM role for sink tests to pass.
  15. // TODO(jba): [cont] (1) From top left menu, go to IAM & Admin. (2) In Roles dropdown for acct, select Logging > Logs Configuration Writer. (3) Save.
  16. // TODO(jba): Also, cloud-logs@google.com must have Owner permission on the GCS bucket named for the test project.
  17. package logadmin
  18. import (
  19. "log"
  20. "testing"
  21. "time"
  22. "cloud.google.com/go/internal/testutil"
  23. "cloud.google.com/go/internal/uid"
  24. "cloud.google.com/go/storage"
  25. "golang.org/x/net/context"
  26. "google.golang.org/api/iterator"
  27. "google.golang.org/api/option"
  28. )
  29. var sinkIDs = uid.NewSpace("GO-CLIENT-TEST-SINK", nil)
  30. const testFilter = ""
  31. var testSinkDestination string
  32. // Called just before TestMain calls m.Run.
  33. // Returns a cleanup function to be called after the tests finish.
  34. func initSinks(ctx context.Context) func() {
  35. // Create a unique GCS bucket so concurrent tests don't interfere with each other.
  36. bucketIDs := uid.NewSpace(testProjectID+"-log-sink", nil)
  37. testBucket := bucketIDs.New()
  38. testSinkDestination = "storage.googleapis.com/" + testBucket
  39. var storageClient *storage.Client
  40. if integrationTest {
  41. // Create a unique bucket as a sink destination, and give the cloud logging account
  42. // owner right.
  43. ts := testutil.TokenSource(ctx, storage.ScopeFullControl)
  44. var err error
  45. storageClient, err = storage.NewClient(ctx, option.WithTokenSource(ts))
  46. if err != nil {
  47. log.Fatalf("new storage client: %v", err)
  48. }
  49. bucket := storageClient.Bucket(testBucket)
  50. if err := bucket.Create(ctx, testProjectID, nil); err != nil {
  51. log.Fatalf("creating storage bucket %q: %v", testBucket, err)
  52. }
  53. if err := bucket.ACL().Set(ctx, "group-cloud-logs@google.com", storage.RoleOwner); err != nil {
  54. log.Fatalf("setting owner role: %v", err)
  55. }
  56. }
  57. // Clean up from aborted tests.
  58. it := client.Sinks(ctx)
  59. for {
  60. s, err := it.Next()
  61. if err == iterator.Done {
  62. break
  63. }
  64. if err != nil {
  65. log.Printf("listing sinks: %v", err)
  66. break
  67. }
  68. if sinkIDs.Older(s.ID, 24*time.Hour) {
  69. client.DeleteSink(ctx, s.ID) // ignore error
  70. }
  71. }
  72. if integrationTest {
  73. for _, bn := range bucketNames(ctx, storageClient) {
  74. if bucketIDs.Older(bn, 24*time.Hour) {
  75. storageClient.Bucket(bn).Delete(ctx) // ignore error
  76. }
  77. }
  78. return func() {
  79. if err := storageClient.Bucket(testBucket).Delete(ctx); err != nil {
  80. log.Printf("deleting %q: %v", testBucket, err)
  81. }
  82. storageClient.Close()
  83. }
  84. }
  85. return func() {}
  86. }
  87. // Collect the name of all buckets for the test project.
  88. func bucketNames(ctx context.Context, client *storage.Client) []string {
  89. var names []string
  90. it := client.Buckets(ctx, testProjectID)
  91. loop:
  92. for {
  93. b, err := it.Next()
  94. switch err {
  95. case nil:
  96. names = append(names, b.Name)
  97. case iterator.Done:
  98. break loop
  99. default:
  100. log.Printf("listing buckets: %v", err)
  101. break loop
  102. }
  103. }
  104. return names
  105. }
  106. func TestCreateDeleteSink(t *testing.T) {
  107. ctx := context.Background()
  108. sink := &Sink{
  109. ID: sinkIDs.New(),
  110. Destination: testSinkDestination,
  111. Filter: testFilter,
  112. }
  113. got, err := client.CreateSink(ctx, sink)
  114. if err != nil {
  115. t.Fatal(err)
  116. }
  117. defer client.DeleteSink(ctx, sink.ID)
  118. if want := sink; !testutil.Equal(got, want) {
  119. t.Errorf("got %+v, want %+v", got, want)
  120. }
  121. got, err = client.Sink(ctx, sink.ID)
  122. if err != nil {
  123. t.Fatal(err)
  124. }
  125. if want := sink; !testutil.Equal(got, want) {
  126. t.Errorf("got %+v, want %+v", got, want)
  127. }
  128. if err := client.DeleteSink(ctx, sink.ID); err != nil {
  129. t.Fatal(err)
  130. }
  131. if _, err := client.Sink(ctx, sink.ID); err == nil {
  132. t.Fatal("got no error, expected one")
  133. }
  134. }
  135. func TestUpdateSink(t *testing.T) {
  136. ctx := context.Background()
  137. sink := &Sink{
  138. ID: sinkIDs.New(),
  139. Destination: testSinkDestination,
  140. Filter: testFilter,
  141. }
  142. if _, err := client.CreateSink(ctx, sink); err != nil {
  143. t.Fatal(err)
  144. }
  145. got, err := client.UpdateSink(ctx, sink)
  146. if err != nil {
  147. t.Fatal(err)
  148. }
  149. defer client.DeleteSink(ctx, sink.ID)
  150. if want := sink; !testutil.Equal(got, want) {
  151. t.Errorf("got %+v, want %+v", got, want)
  152. }
  153. got, err = client.Sink(ctx, sink.ID)
  154. if err != nil {
  155. t.Fatal(err)
  156. }
  157. if want := sink; !testutil.Equal(got, want) {
  158. t.Errorf("got %+v, want %+v", got, want)
  159. }
  160. // Updating an existing sink changes it.
  161. sink.Filter = ""
  162. if _, err := client.UpdateSink(ctx, sink); err != nil {
  163. t.Fatal(err)
  164. }
  165. got, err = client.Sink(ctx, sink.ID)
  166. if err != nil {
  167. t.Fatal(err)
  168. }
  169. if want := sink; !testutil.Equal(got, want) {
  170. t.Errorf("got %+v, want %+v", got, want)
  171. }
  172. }
  173. func TestListSinks(t *testing.T) {
  174. ctx := context.Background()
  175. var sinks []*Sink
  176. want := map[string]*Sink{}
  177. for i := 0; i < 4; i++ {
  178. s := &Sink{
  179. ID: sinkIDs.New(),
  180. Destination: testSinkDestination,
  181. Filter: testFilter,
  182. }
  183. sinks = append(sinks, s)
  184. want[s.ID] = s
  185. }
  186. for _, s := range sinks {
  187. if _, err := client.CreateSink(ctx, s); err != nil {
  188. t.Fatalf("Create(%q): %v", s.ID, err)
  189. }
  190. defer client.DeleteSink(ctx, s.ID)
  191. }
  192. got := map[string]*Sink{}
  193. it := client.Sinks(ctx)
  194. for {
  195. s, err := it.Next()
  196. if err == iterator.Done {
  197. break
  198. }
  199. if err != nil {
  200. t.Fatal(err)
  201. }
  202. // If tests run simultaneously, we may have more sinks than we
  203. // created. So only check for our own.
  204. if _, ok := want[s.ID]; ok {
  205. got[s.ID] = s
  206. }
  207. }
  208. if !testutil.Equal(got, want) {
  209. t.Errorf("got %+v, want %+v", got, want)
  210. }
  211. }