Loading core/java/com/android/internal/protolog/ProtoLogCommandHandler.java 0 → 100644 +172 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 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.android.internal.protolog; import android.annotation.NonNull; import android.annotation.Nullable; import android.os.ShellCommand; import com.android.internal.annotations.VisibleForTesting; import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; import java.util.Set; public class ProtoLogCommandHandler extends ShellCommand { @NonNull private final ProtoLogService mProtoLogService; @Nullable private final PrintWriter mPrintWriter; public ProtoLogCommandHandler(@NonNull ProtoLogService protoLogService) { this(protoLogService, null); } @VisibleForTesting public ProtoLogCommandHandler( @NonNull ProtoLogService protoLogService, @Nullable PrintWriter printWriter) { this.mProtoLogService = protoLogService; this.mPrintWriter = printWriter; } @Override public int onCommand(String cmd) { if (cmd == null) { onHelp(); return 0; } return switch (cmd) { case "groups" -> handleGroupsCommands(getNextArg()); case "logcat" -> handleLogcatCommands(getNextArg()); default -> handleDefaultCommands(cmd); }; } @Override public void onHelp() { PrintWriter pw = getOutPrintWriter(); pw.println("ProtoLog commands:"); pw.println(" help"); pw.println(" Print this help text."); pw.println(); pw.println(" groups (list | status)"); pw.println(" list - lists all ProtoLog groups registered with ProtoLog service"); pw.println(" status <group> - print the status of a ProtoLog group"); pw.println(); pw.println(" logcat (enable | disable) <group>"); pw.println(" enable or disable ProtoLog to logcat"); pw.println(); } @NonNull @Override public PrintWriter getOutPrintWriter() { if (mPrintWriter != null) { return mPrintWriter; } return super.getOutPrintWriter(); } private int handleGroupsCommands(@Nullable String cmd) { PrintWriter pw = getOutPrintWriter(); if (cmd == null) { pw.println("Incomplete command. Use 'cmd protolog help' for guidance."); return 0; } switch (cmd) { case "list": { final String[] availableGroups = mProtoLogService.getGroups(); if (availableGroups.length == 0) { pw.println("No ProtoLog groups registered with ProtoLog service."); return 0; } pw.println("ProtoLog groups registered with service:"); for (String group : availableGroups) { pw.println("- " + group); } return 0; } case "status": { final String group = getNextArg(); if (group == null) { pw.println("Incomplete command. Use 'cmd protolog help' for guidance."); return 0; } pw.println("ProtoLog group " + group + "'s status:"); if (!Set.of(mProtoLogService.getGroups()).contains(group)) { pw.println("UNREGISTERED"); return 0; } pw.println("LOG_TO_LOGCAT = " + mProtoLogService.isLoggingToLogcat(group)); return 0; } default: { pw.println("Unknown command: " + cmd); return -1; } } } private int handleLogcatCommands(@Nullable String cmd) { PrintWriter pw = getOutPrintWriter(); if (cmd == null || peekNextArg() == null) { pw.println("Incomplete command. Use 'cmd protolog help' for guidance."); return 0; } switch (cmd) { case "enable" -> { mProtoLogService.enableProtoLogToLogcat(processGroups()); return 0; } case "disable" -> { mProtoLogService.disableProtoLogToLogcat(processGroups()); return 0; } default -> { pw.println("Unknown command: " + cmd); return -1; } } } @NonNull private String[] processGroups() { if (getRemainingArgsCount() == 0) { return mProtoLogService.getGroups(); } final List<String> groups = new ArrayList<>(); while (getRemainingArgsCount() > 0) { groups.add(getNextArg()); } return groups.toArray(new String[0]); } } core/java/com/android/internal/protolog/ProtoLogService.java +11 −0 Original line number Diff line number Diff line Loading @@ -33,6 +33,8 @@ import android.annotation.Nullable; import android.annotation.SystemService; import android.content.Context; import android.os.RemoteException; import android.os.ResultReceiver; import android.os.ShellCallback; import android.os.SystemClock; import android.tracing.perfetto.DataSourceParams; import android.tracing.perfetto.InitArguments; Loading @@ -43,6 +45,7 @@ import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.VisibleForTesting; import java.io.FileDescriptor; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; Loading Loading @@ -224,6 +227,14 @@ public final class ProtoLogService extends IProtoLogService.Stub { registerGroups(client, args.getGroups(), args.getGroupsDefaultLogcatStatus()); } @Override public void onShellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out, @Nullable FileDescriptor err, @NonNull String[] args, @Nullable ShellCallback callback, @NonNull ResultReceiver resultReceiver) throws RemoteException { new ProtoLogCommandHandler(this) .exec(this, in, out, err, args, callback, resultReceiver); } /** * Get the list of groups clients have registered to the protolog service. * @return The list of ProtoLog groups registered with this service. Loading tests/Internal/src/com/android/internal/protolog/ProtoLogCommandHandlerTest.java 0 → 100644 +207 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 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.android.internal.protolog; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.contains; import static org.mockito.ArgumentMatchers.endsWith; import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.times; import android.platform.test.annotations.Presubmit; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.junit.MockitoJUnitRunner; import java.io.FileDescriptor; import java.io.PrintWriter; /** * Test class for {@link ProtoLogImpl}. */ @Presubmit @RunWith(MockitoJUnitRunner.class) public class ProtoLogCommandHandlerTest { @Mock ProtoLogService mProtoLogService; @Mock PrintWriter mPrintWriter; @Test public void printsHelpForAllAvailableCommands() { final ProtoLogCommandHandler cmdHandler = new ProtoLogCommandHandler(mProtoLogService, mPrintWriter); cmdHandler.onHelp(); validateOnHelpPrinted(); } @Test public void printsHelpIfCommandIsNull() { final ProtoLogCommandHandler cmdHandler = new ProtoLogCommandHandler(mProtoLogService, mPrintWriter); cmdHandler.onCommand(null); validateOnHelpPrinted(); } @Test public void handlesGroupListCommand() { Mockito.when(mProtoLogService.getGroups()) .thenReturn(new String[] {"MY_TEST_GROUP", "MY_OTHER_GROUP"}); final ProtoLogCommandHandler cmdHandler = new ProtoLogCommandHandler(mProtoLogService, mPrintWriter); cmdHandler.exec(mProtoLogService, FileDescriptor.in, FileDescriptor.out, FileDescriptor.err, new String[] { "groups", "list" }); Mockito.verify(mPrintWriter, times(1)) .println(contains("MY_TEST_GROUP")); Mockito.verify(mPrintWriter, times(1)) .println(contains("MY_OTHER_GROUP")); } @Test public void handlesIncompleteGroupsCommand() { final ProtoLogCommandHandler cmdHandler = new ProtoLogCommandHandler(mProtoLogService, mPrintWriter); cmdHandler.exec(mProtoLogService, FileDescriptor.in, FileDescriptor.out, FileDescriptor.err, new String[] { "groups" }); Mockito.verify(mPrintWriter, times(1)) .println(contains("Incomplete command")); } @Test public void handlesGroupStatusCommand() { Mockito.when(mProtoLogService.getGroups()).thenReturn(new String[] {"MY_GROUP"}); Mockito.when(mProtoLogService.isLoggingToLogcat("MY_GROUP")).thenReturn(true); final ProtoLogCommandHandler cmdHandler = new ProtoLogCommandHandler(mProtoLogService, mPrintWriter); cmdHandler.exec(mProtoLogService, FileDescriptor.in, FileDescriptor.out, FileDescriptor.err, new String[] { "groups", "status", "MY_GROUP" }); Mockito.verify(mPrintWriter, times(1)) .println(contains("MY_GROUP")); Mockito.verify(mPrintWriter, times(1)) .println(contains("LOG_TO_LOGCAT = true")); } @Test public void handlesGroupStatusCommandOfUnregisteredGroups() { Mockito.when(mProtoLogService.getGroups()).thenReturn(new String[] {}); final ProtoLogCommandHandler cmdHandler = new ProtoLogCommandHandler(mProtoLogService, mPrintWriter); cmdHandler.exec(mProtoLogService, FileDescriptor.in, FileDescriptor.out, FileDescriptor.err, new String[] { "groups", "status", "MY_GROUP" }); Mockito.verify(mPrintWriter, times(1)) .println(contains("MY_GROUP")); Mockito.verify(mPrintWriter, times(1)) .println(contains("UNREGISTERED")); } @Test public void handlesGroupStatusCommandWithNoGroups() { final ProtoLogCommandHandler cmdHandler = new ProtoLogCommandHandler(mProtoLogService, mPrintWriter); cmdHandler.exec(mProtoLogService, FileDescriptor.in, FileDescriptor.out, FileDescriptor.err, new String[] { "groups", "status" }); Mockito.verify(mPrintWriter, times(1)) .println(contains("Incomplete command")); } @Test public void handlesIncompleteLogcatCommand() { final ProtoLogCommandHandler cmdHandler = new ProtoLogCommandHandler(mProtoLogService, mPrintWriter); cmdHandler.exec(mProtoLogService, FileDescriptor.in, FileDescriptor.out, FileDescriptor.err, new String[] { "logcat" }); Mockito.verify(mPrintWriter, times(1)) .println(contains("Incomplete command")); } @Test public void handlesLogcatEnableCommand() { final ProtoLogCommandHandler cmdHandler = new ProtoLogCommandHandler(mProtoLogService, mPrintWriter); cmdHandler.exec(mProtoLogService, FileDescriptor.in, FileDescriptor.out, FileDescriptor.err, new String[] { "logcat", "enable", "MY_GROUP" }); Mockito.verify(mProtoLogService).enableProtoLogToLogcat("MY_GROUP"); cmdHandler.exec(mProtoLogService, FileDescriptor.in, FileDescriptor.out, FileDescriptor.err, new String[] { "logcat", "enable", "MY_GROUP", "MY_OTHER_GROUP" }); Mockito.verify(mProtoLogService) .enableProtoLogToLogcat("MY_GROUP", "MY_OTHER_GROUP"); } @Test public void handlesLogcatDisableCommand() { final ProtoLogCommandHandler cmdHandler = new ProtoLogCommandHandler(mProtoLogService, mPrintWriter); cmdHandler.exec(mProtoLogService, FileDescriptor.in, FileDescriptor.out, FileDescriptor.err, new String[] { "logcat", "disable", "MY_GROUP" }); Mockito.verify(mProtoLogService).disableProtoLogToLogcat("MY_GROUP"); cmdHandler.exec(mProtoLogService, FileDescriptor.in, FileDescriptor.out, FileDescriptor.err, new String[] { "logcat", "disable", "MY_GROUP", "MY_OTHER_GROUP" }); Mockito.verify(mProtoLogService) .disableProtoLogToLogcat("MY_GROUP", "MY_OTHER_GROUP"); } @Test public void handlesLogcatEnableCommandWithNoGroups() { final ProtoLogCommandHandler cmdHandler = new ProtoLogCommandHandler(mProtoLogService, mPrintWriter); cmdHandler.exec(mProtoLogService, FileDescriptor.in, FileDescriptor.out, FileDescriptor.err, new String[] { "logcat", "enable" }); Mockito.verify(mPrintWriter).println(contains("Incomplete command")); } @Test public void handlesLogcatDisableCommandWithNoGroups() { final ProtoLogCommandHandler cmdHandler = new ProtoLogCommandHandler(mProtoLogService, mPrintWriter); cmdHandler.exec(mProtoLogService, FileDescriptor.in, FileDescriptor.out, FileDescriptor.err, new String[] { "logcat", "disable" }); Mockito.verify(mPrintWriter).println(contains("Incomplete command")); } private void validateOnHelpPrinted() { Mockito.verify(mPrintWriter, times(1)).println(endsWith("help")); Mockito.verify(mPrintWriter, times(1)) .println(endsWith("groups (list | status)")); Mockito.verify(mPrintWriter, times(1)) .println(endsWith("logcat (enable | disable) <group>")); Mockito.verify(mPrintWriter, atLeast(0)).println(anyString()); } } Loading
core/java/com/android/internal/protolog/ProtoLogCommandHandler.java 0 → 100644 +172 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 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.android.internal.protolog; import android.annotation.NonNull; import android.annotation.Nullable; import android.os.ShellCommand; import com.android.internal.annotations.VisibleForTesting; import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; import java.util.Set; public class ProtoLogCommandHandler extends ShellCommand { @NonNull private final ProtoLogService mProtoLogService; @Nullable private final PrintWriter mPrintWriter; public ProtoLogCommandHandler(@NonNull ProtoLogService protoLogService) { this(protoLogService, null); } @VisibleForTesting public ProtoLogCommandHandler( @NonNull ProtoLogService protoLogService, @Nullable PrintWriter printWriter) { this.mProtoLogService = protoLogService; this.mPrintWriter = printWriter; } @Override public int onCommand(String cmd) { if (cmd == null) { onHelp(); return 0; } return switch (cmd) { case "groups" -> handleGroupsCommands(getNextArg()); case "logcat" -> handleLogcatCommands(getNextArg()); default -> handleDefaultCommands(cmd); }; } @Override public void onHelp() { PrintWriter pw = getOutPrintWriter(); pw.println("ProtoLog commands:"); pw.println(" help"); pw.println(" Print this help text."); pw.println(); pw.println(" groups (list | status)"); pw.println(" list - lists all ProtoLog groups registered with ProtoLog service"); pw.println(" status <group> - print the status of a ProtoLog group"); pw.println(); pw.println(" logcat (enable | disable) <group>"); pw.println(" enable or disable ProtoLog to logcat"); pw.println(); } @NonNull @Override public PrintWriter getOutPrintWriter() { if (mPrintWriter != null) { return mPrintWriter; } return super.getOutPrintWriter(); } private int handleGroupsCommands(@Nullable String cmd) { PrintWriter pw = getOutPrintWriter(); if (cmd == null) { pw.println("Incomplete command. Use 'cmd protolog help' for guidance."); return 0; } switch (cmd) { case "list": { final String[] availableGroups = mProtoLogService.getGroups(); if (availableGroups.length == 0) { pw.println("No ProtoLog groups registered with ProtoLog service."); return 0; } pw.println("ProtoLog groups registered with service:"); for (String group : availableGroups) { pw.println("- " + group); } return 0; } case "status": { final String group = getNextArg(); if (group == null) { pw.println("Incomplete command. Use 'cmd protolog help' for guidance."); return 0; } pw.println("ProtoLog group " + group + "'s status:"); if (!Set.of(mProtoLogService.getGroups()).contains(group)) { pw.println("UNREGISTERED"); return 0; } pw.println("LOG_TO_LOGCAT = " + mProtoLogService.isLoggingToLogcat(group)); return 0; } default: { pw.println("Unknown command: " + cmd); return -1; } } } private int handleLogcatCommands(@Nullable String cmd) { PrintWriter pw = getOutPrintWriter(); if (cmd == null || peekNextArg() == null) { pw.println("Incomplete command. Use 'cmd protolog help' for guidance."); return 0; } switch (cmd) { case "enable" -> { mProtoLogService.enableProtoLogToLogcat(processGroups()); return 0; } case "disable" -> { mProtoLogService.disableProtoLogToLogcat(processGroups()); return 0; } default -> { pw.println("Unknown command: " + cmd); return -1; } } } @NonNull private String[] processGroups() { if (getRemainingArgsCount() == 0) { return mProtoLogService.getGroups(); } final List<String> groups = new ArrayList<>(); while (getRemainingArgsCount() > 0) { groups.add(getNextArg()); } return groups.toArray(new String[0]); } }
core/java/com/android/internal/protolog/ProtoLogService.java +11 −0 Original line number Diff line number Diff line Loading @@ -33,6 +33,8 @@ import android.annotation.Nullable; import android.annotation.SystemService; import android.content.Context; import android.os.RemoteException; import android.os.ResultReceiver; import android.os.ShellCallback; import android.os.SystemClock; import android.tracing.perfetto.DataSourceParams; import android.tracing.perfetto.InitArguments; Loading @@ -43,6 +45,7 @@ import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.VisibleForTesting; import java.io.FileDescriptor; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; Loading Loading @@ -224,6 +227,14 @@ public final class ProtoLogService extends IProtoLogService.Stub { registerGroups(client, args.getGroups(), args.getGroupsDefaultLogcatStatus()); } @Override public void onShellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out, @Nullable FileDescriptor err, @NonNull String[] args, @Nullable ShellCallback callback, @NonNull ResultReceiver resultReceiver) throws RemoteException { new ProtoLogCommandHandler(this) .exec(this, in, out, err, args, callback, resultReceiver); } /** * Get the list of groups clients have registered to the protolog service. * @return The list of ProtoLog groups registered with this service. Loading
tests/Internal/src/com/android/internal/protolog/ProtoLogCommandHandlerTest.java 0 → 100644 +207 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 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.android.internal.protolog; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.contains; import static org.mockito.ArgumentMatchers.endsWith; import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.times; import android.platform.test.annotations.Presubmit; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.junit.MockitoJUnitRunner; import java.io.FileDescriptor; import java.io.PrintWriter; /** * Test class for {@link ProtoLogImpl}. */ @Presubmit @RunWith(MockitoJUnitRunner.class) public class ProtoLogCommandHandlerTest { @Mock ProtoLogService mProtoLogService; @Mock PrintWriter mPrintWriter; @Test public void printsHelpForAllAvailableCommands() { final ProtoLogCommandHandler cmdHandler = new ProtoLogCommandHandler(mProtoLogService, mPrintWriter); cmdHandler.onHelp(); validateOnHelpPrinted(); } @Test public void printsHelpIfCommandIsNull() { final ProtoLogCommandHandler cmdHandler = new ProtoLogCommandHandler(mProtoLogService, mPrintWriter); cmdHandler.onCommand(null); validateOnHelpPrinted(); } @Test public void handlesGroupListCommand() { Mockito.when(mProtoLogService.getGroups()) .thenReturn(new String[] {"MY_TEST_GROUP", "MY_OTHER_GROUP"}); final ProtoLogCommandHandler cmdHandler = new ProtoLogCommandHandler(mProtoLogService, mPrintWriter); cmdHandler.exec(mProtoLogService, FileDescriptor.in, FileDescriptor.out, FileDescriptor.err, new String[] { "groups", "list" }); Mockito.verify(mPrintWriter, times(1)) .println(contains("MY_TEST_GROUP")); Mockito.verify(mPrintWriter, times(1)) .println(contains("MY_OTHER_GROUP")); } @Test public void handlesIncompleteGroupsCommand() { final ProtoLogCommandHandler cmdHandler = new ProtoLogCommandHandler(mProtoLogService, mPrintWriter); cmdHandler.exec(mProtoLogService, FileDescriptor.in, FileDescriptor.out, FileDescriptor.err, new String[] { "groups" }); Mockito.verify(mPrintWriter, times(1)) .println(contains("Incomplete command")); } @Test public void handlesGroupStatusCommand() { Mockito.when(mProtoLogService.getGroups()).thenReturn(new String[] {"MY_GROUP"}); Mockito.when(mProtoLogService.isLoggingToLogcat("MY_GROUP")).thenReturn(true); final ProtoLogCommandHandler cmdHandler = new ProtoLogCommandHandler(mProtoLogService, mPrintWriter); cmdHandler.exec(mProtoLogService, FileDescriptor.in, FileDescriptor.out, FileDescriptor.err, new String[] { "groups", "status", "MY_GROUP" }); Mockito.verify(mPrintWriter, times(1)) .println(contains("MY_GROUP")); Mockito.verify(mPrintWriter, times(1)) .println(contains("LOG_TO_LOGCAT = true")); } @Test public void handlesGroupStatusCommandOfUnregisteredGroups() { Mockito.when(mProtoLogService.getGroups()).thenReturn(new String[] {}); final ProtoLogCommandHandler cmdHandler = new ProtoLogCommandHandler(mProtoLogService, mPrintWriter); cmdHandler.exec(mProtoLogService, FileDescriptor.in, FileDescriptor.out, FileDescriptor.err, new String[] { "groups", "status", "MY_GROUP" }); Mockito.verify(mPrintWriter, times(1)) .println(contains("MY_GROUP")); Mockito.verify(mPrintWriter, times(1)) .println(contains("UNREGISTERED")); } @Test public void handlesGroupStatusCommandWithNoGroups() { final ProtoLogCommandHandler cmdHandler = new ProtoLogCommandHandler(mProtoLogService, mPrintWriter); cmdHandler.exec(mProtoLogService, FileDescriptor.in, FileDescriptor.out, FileDescriptor.err, new String[] { "groups", "status" }); Mockito.verify(mPrintWriter, times(1)) .println(contains("Incomplete command")); } @Test public void handlesIncompleteLogcatCommand() { final ProtoLogCommandHandler cmdHandler = new ProtoLogCommandHandler(mProtoLogService, mPrintWriter); cmdHandler.exec(mProtoLogService, FileDescriptor.in, FileDescriptor.out, FileDescriptor.err, new String[] { "logcat" }); Mockito.verify(mPrintWriter, times(1)) .println(contains("Incomplete command")); } @Test public void handlesLogcatEnableCommand() { final ProtoLogCommandHandler cmdHandler = new ProtoLogCommandHandler(mProtoLogService, mPrintWriter); cmdHandler.exec(mProtoLogService, FileDescriptor.in, FileDescriptor.out, FileDescriptor.err, new String[] { "logcat", "enable", "MY_GROUP" }); Mockito.verify(mProtoLogService).enableProtoLogToLogcat("MY_GROUP"); cmdHandler.exec(mProtoLogService, FileDescriptor.in, FileDescriptor.out, FileDescriptor.err, new String[] { "logcat", "enable", "MY_GROUP", "MY_OTHER_GROUP" }); Mockito.verify(mProtoLogService) .enableProtoLogToLogcat("MY_GROUP", "MY_OTHER_GROUP"); } @Test public void handlesLogcatDisableCommand() { final ProtoLogCommandHandler cmdHandler = new ProtoLogCommandHandler(mProtoLogService, mPrintWriter); cmdHandler.exec(mProtoLogService, FileDescriptor.in, FileDescriptor.out, FileDescriptor.err, new String[] { "logcat", "disable", "MY_GROUP" }); Mockito.verify(mProtoLogService).disableProtoLogToLogcat("MY_GROUP"); cmdHandler.exec(mProtoLogService, FileDescriptor.in, FileDescriptor.out, FileDescriptor.err, new String[] { "logcat", "disable", "MY_GROUP", "MY_OTHER_GROUP" }); Mockito.verify(mProtoLogService) .disableProtoLogToLogcat("MY_GROUP", "MY_OTHER_GROUP"); } @Test public void handlesLogcatEnableCommandWithNoGroups() { final ProtoLogCommandHandler cmdHandler = new ProtoLogCommandHandler(mProtoLogService, mPrintWriter); cmdHandler.exec(mProtoLogService, FileDescriptor.in, FileDescriptor.out, FileDescriptor.err, new String[] { "logcat", "enable" }); Mockito.verify(mPrintWriter).println(contains("Incomplete command")); } @Test public void handlesLogcatDisableCommandWithNoGroups() { final ProtoLogCommandHandler cmdHandler = new ProtoLogCommandHandler(mProtoLogService, mPrintWriter); cmdHandler.exec(mProtoLogService, FileDescriptor.in, FileDescriptor.out, FileDescriptor.err, new String[] { "logcat", "disable" }); Mockito.verify(mPrintWriter).println(contains("Incomplete command")); } private void validateOnHelpPrinted() { Mockito.verify(mPrintWriter, times(1)).println(endsWith("help")); Mockito.verify(mPrintWriter, times(1)) .println(endsWith("groups (list | status)")); Mockito.verify(mPrintWriter, times(1)) .println(endsWith("logcat (enable | disable) <group>")); Mockito.verify(mPrintWriter, atLeast(0)).println(anyString()); } }