| // Copyright (C) 2018 The Android Open Source Project | 
 | // | 
 | // Licensed under the Apache License, Version 2.0 (the "License"); | 
 | // you may not use this file except in compliance with the License. | 
 | // You may obtain a copy of the License at | 
 | // | 
 | // http://www.apache.org/licenses/LICENSE-2.0 | 
 | // | 
 | // Unless required by applicable law or agreed to in writing, software | 
 | // distributed under the License is distributed on an "AS IS" BASIS, | 
 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 | // See the License for the specific language governing permissions and | 
 | // limitations under the License. | 
 |  | 
 | package com.google.gerrit.acceptance; | 
 |  | 
 | import static java.util.Comparator.comparing; | 
 | import static java.util.concurrent.TimeUnit.SECONDS; | 
 |  | 
 | import com.google.common.collect.ImmutableList; | 
 | import com.google.common.primitives.Ints; | 
 | import com.google.gerrit.extensions.registration.DynamicSet; | 
 | import com.google.gerrit.httpd.GitOverHttpServlet; | 
 | import com.google.gerrit.server.AuditEvent; | 
 | import com.google.gerrit.server.audit.AuditListener; | 
 | import com.google.gerrit.server.audit.AuditService; | 
 | import com.google.gerrit.server.audit.HttpAuditEvent; | 
 | import com.google.gerrit.server.audit.group.GroupAuditListener; | 
 | import com.google.gerrit.server.group.GroupAuditService; | 
 | import com.google.gerrit.server.plugincontext.PluginSetContext; | 
 | import com.google.inject.AbstractModule; | 
 | import com.google.inject.Inject; | 
 | import com.google.inject.Singleton; | 
 | import java.util.ArrayList; | 
 | import java.util.List; | 
 | import java.util.concurrent.BlockingQueue; | 
 | import java.util.concurrent.LinkedBlockingQueue; | 
 | import java.util.concurrent.atomic.AtomicLong; | 
 |  | 
 | @Singleton | 
 | public class FakeGroupAuditService extends AuditService { | 
 |   public static class Module extends AbstractModule { | 
 |     @Override | 
 |     public void configure() { | 
 |       DynamicSet.setOf(binder(), GroupAuditListener.class); | 
 |       DynamicSet.setOf(binder(), AuditListener.class); | 
 |  | 
 |       // Use this fake service at the Guice level rather than depending on tests binding their own | 
 |       // audit listeners. If we used per-test listeners, then there would be a race between | 
 |       // dispatching the audit events from HTTP requests performed during test setup in | 
 |       // AbstractDaemonTest, and the later test setup binding the audit listener. Using a separate | 
 |       // audit service implementation ensures all events get recorded. | 
 |       bind(GroupAuditService.class).to(FakeGroupAuditService.class); | 
 |     } | 
 |   } | 
 |  | 
 |   private final GitOverHttpServlet.Metrics httpMetrics; | 
 |   private final BlockingQueue<HttpAuditEvent> httpEvents; | 
 |   private final AtomicLong drainedSoFar; | 
 |  | 
 |   @Inject | 
 |   FakeGroupAuditService( | 
 |       PluginSetContext<AuditListener> auditListeners, | 
 |       PluginSetContext<GroupAuditListener> groupAuditListeners, | 
 |       GitOverHttpServlet.Metrics httpMetrics) { | 
 |     super(auditListeners, groupAuditListeners); | 
 |     this.httpMetrics = httpMetrics; | 
 |     this.httpEvents = new LinkedBlockingQueue<>(); | 
 |     this.drainedSoFar = new AtomicLong(); | 
 |   } | 
 |  | 
 |   @Override | 
 |   public void dispatch(AuditEvent action) { | 
 |     super.dispatch(action); | 
 |     if (action instanceof HttpAuditEvent) { | 
 |       httpEvents.add((HttpAuditEvent) action); | 
 |     } | 
 |   } | 
 |  | 
 |   public ImmutableList<HttpAuditEvent> drainHttpAuditEvents() throws Exception { | 
 |     // Assumes that all HttpAuditEvents are produced by GitOverHttpServlet. | 
 |     int expectedSize = Ints.checkedCast(httpMetrics.getRequestsStarted() - drainedSoFar.get()); | 
 |     List<HttpAuditEvent> result = new ArrayList<>(); | 
 |     for (int i = 0; i < expectedSize; i++) { | 
 |       HttpAuditEvent e = httpEvents.poll(30, SECONDS); | 
 |       if (e == null) { | 
 |         throw new AssertionError( | 
 |             String.format("Timeout after receiving %d/%d audit events", i, expectedSize)); | 
 |       } | 
 |       drainedSoFar.incrementAndGet(); | 
 |       result.add(e); | 
 |     } | 
 |     return ImmutableList.sortedCopyOf(comparing(e -> e.when), result); | 
 |   } | 
 | } |