Skip to content
This repository has been archived by the owner on Jan 11, 2022. It is now read-only.

Commit

Permalink
Set up analytics infrastructure (#85)
Browse files Browse the repository at this point in the history
  • Loading branch information
etanshaul authored Dec 11, 2018
1 parent c713441 commit 02f411e
Show file tree
Hide file tree
Showing 12 changed files with 412 additions and 1 deletion.
16 changes: 16 additions & 0 deletions core/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,20 @@

dependencies {
testCompile(project(":common-test-lib"))

// TODO replace with maven central dependency once published
compile(files("../lib/ide-analytics-common-0.1.0-SNAPSHOT.jar"))
}

// Processes the analytics id environment variable value into the analyticsId property
// in config.properties
val processResources by tasks.getting(ProcessResources::class) {
val analyticsId: String? = System.getenv("ANALYTICS_ID")

analyticsId?.let {
inputs.property("analyticsId", analyticsId)
filesMatching("**/config.properties") {
expand(mutableMapOf("analyticsId" to analyticsId))
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ class PluginInfo {
companion object {
private const val UNKNOWN_VERSION = "unknown"
const val CONTAINER_TOOLS_PLUGIN_ID = "com.google.container.tools"
const val PLUGIN_NAME_EXTERNAL = "google-container-tools-intellij"
const val PLUGIN_USER_AGENT = "google-container-tools-intellij-plugin"

val instance: PluginInfo
get() = ServiceManager.getService(PluginInfo::class.java)!!
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* Copyright 2018 Google Inc. All Rights Reserved.
*
* 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.container.tools.core.analytics

import com.google.common.annotations.VisibleForTesting
import com.google.container.tools.core.properties.PluginPropertiesFileReader
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.components.ServiceManager

/**
* Application service that manages the status of usage tracking in the plugin.
*/
class UsageTrackerManagerService {

companion object {
private const val ANALYTICS_ID_KEY = "analytics.id"
private const val ANALYTICS_ID_PLACEHOLDER_VAL = "\${analyticsId}"

val instance
get() = ServiceManager.getService(UsageTrackerManagerService::class.java)!!
}

/**
* Returns true if usage tracking is enabled, and false otherwise. Usage tracking is enabled if
* the Analytics ID is configured and we are not running from unit test mode (we don't want to
* send pings from unit tests).
*
* TODO (next PR): add in bit that checks if the user has not opted out of tracking
*/
fun isUsageTrackingEnabled() =
getAnalyticsId() != null && !ApplicationManager.getApplication().isUnitTestMode

/**
* Returns the analytics ID as configured in the properties file. If the analytics ID
* placeholder has not been substituted, then this will return null.
*/
@VisibleForTesting
fun getAnalyticsId(): String? {
val analyticsId: String? =
PluginPropertiesFileReader.instance.getPropertyValue(ANALYTICS_ID_KEY)

return if (ANALYTICS_ID_PLACEHOLDER_VAL != analyticsId) analyticsId else null
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
* Copyright 2018 Google Inc. All Rights Reserved.
*
* 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.container.tools.core.analytics

import com.google.cloud.tools.ide.analytics.UsageTracker
import com.google.cloud.tools.ide.analytics.UsageTrackerSettings
import com.google.container.tools.core.PluginInfo
import com.intellij.openapi.application.ApplicationInfo
import com.intellij.openapi.application.PermanentInstallationID
import com.intellij.openapi.components.ServiceManager

/**
* Application service that initializes the [UsageTracker] for analytics. Sets up core components
* of analytics collection such as the analytics ID, user agent, client ID etc.
*
* Example usage:
* ```
* UsageTrackerProvider.instance.usageTracker.trackEvent("event-name").ping()
* ```
*/
class UsageTrackerProvider {

val usageTracker: UsageTracker

init {
val usageTrackerManagerService: UsageTrackerManagerService =
UsageTrackerManagerService.instance

val settings: UsageTrackerSettings = UsageTrackerSettings.Builder()
.manager { usageTrackerManagerService.isUsageTrackingEnabled() }
.analyticsId(usageTrackerManagerService.getAnalyticsId())
.pageHost(PAGE_HOST)
.platformName(PluginInfo.instance.platformPrefix)
.platformVersion(ApplicationInfo.getInstance().strictVersion)
.pluginName(PluginInfo.PLUGIN_NAME_EXTERNAL)
.pluginVersion(PluginInfo.instance.pluginVersion)
.clientId(PermanentInstallationID.get())
.userAgent(PluginInfo.PLUGIN_USER_AGENT)
.build()

usageTracker = UsageTracker.create(settings)
}

companion object {
private const val PAGE_HOST = "virtual.intellij"

val instance
get() = ServiceManager.getService(UsageTrackerProvider::class.java)!!
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* Copyright 2018 Google Inc. All Rights Reserved.
*
* 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.container.tools.core.properties

import com.intellij.openapi.components.ServiceManager
import java.util.Properties

/**
* Reads property values from the specified properties file supplied to the plugin.
*
* @param propertyFilePath the path to the properties file; defaults to 'config.properties' located
* in the root of the module's resources
*/
class PluginPropertiesFileReader(
propertyFilePath: String = DEFAULT_PROPERTIES_FILE_NAME
) {

private val properties: Properties = Properties()

companion object {
private const val DEFAULT_PROPERTIES_FILE_NAME = "/config.properties"

val instance
get() = ServiceManager.getService(PluginPropertiesFileReader::class.java)!!
}

init {
this.javaClass.getResourceAsStream(propertyFilePath)?.use {
properties.load(it)
} ?: throw IllegalArgumentException(
"Failed to load plugin property configuration file: $propertyFilePath"
)
}

/**
* Return the property value given the passed in name.
*/
fun getPropertyValue(propertyKey: String): String? = properties.getProperty(propertyKey)
}
9 changes: 8 additions & 1 deletion core/src/main/resources/META-INF/core.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,12 @@
<idea-plugin>
<extensions defaultExtensionNs="com.intellij">
<applicationService serviceImplementation="com.google.container.tools.core.PluginInfo"/>

<applicationService
serviceImplementation="com.google.container.tools.core.analytics.UsageTrackerProvider"/>
<applicationService
serviceImplementation="com.google.container.tools.core.analytics.UsageTrackerManagerService"/>
<applicationService
serviceImplementation="com.google.container.tools.core.properties.PluginPropertiesFileReader"/>
</extensions>
</idea-plugin>
</idea-plugin>
17 changes: 17 additions & 0 deletions core/src/main/resources/config.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#
# Copyright 2018 Google Inc. All Rights Reserved.
#
# 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.
#

analytics.id=${analyticsId}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
* Copyright 2018 Google Inc. All Rights Reserved.
*
* 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.container.tools.core.analytics

import com.google.common.truth.Truth
import com.google.container.tools.core.properties.PluginPropertiesFileReader
import com.google.container.tools.test.ContainerToolsRule
import com.google.container.tools.test.TestService
import io.mockk.every
import io.mockk.impl.annotations.MockK
import org.junit.Before
import org.junit.Rule
import org.junit.Test

/**
* Tests for [UsageTrackerManagerService].
*/
class UsageTrackerManagerServiceTest {
@get:Rule
val containerToolsRule = ContainerToolsRule(this)

@TestService
@MockK
private lateinit var propertyReader: PluginPropertiesFileReader

private lateinit var usageTrackerManagerService: UsageTrackerManagerService

@Before
fun setUp() {
usageTrackerManagerService = UsageTrackerManagerService()
}

@Test
fun `usage tracking is disabled in unit test mode`() {
// Set the analytics ID to a proper value
val analyticsId = "UA-12345"
mockAnalyticsId(analyticsId)

Truth.assertThat(usageTrackerManagerService.isUsageTrackingEnabled()).isFalse()
}

@Test
fun `get analytics ID when ID has been substituted returns analytics ID`() {
val analyticsId = "UA-12345"
mockAnalyticsId(analyticsId)

Truth.assertThat(usageTrackerManagerService.getAnalyticsId()).isEqualTo(analyticsId)
}

@Test
fun `get analytics ID when property placeholder has not been substituted returns null`() {
val analyticsIdPlaceholder = "\${analyticsId}"
every { propertyReader.getPropertyValue("analytics.id") } answers { analyticsIdPlaceholder }

Truth.assertThat(usageTrackerManagerService.getAnalyticsId()).isNull()
}

private fun mockAnalyticsId(analyticsId: String) {
every { propertyReader.getPropertyValue("analytics.id") } answers { analyticsId }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* Copyright 2018 Google Inc. All Rights Reserved.
*
* 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.container.tools.core.analytics

import com.google.common.truth.Truth
import com.google.container.tools.core.PluginInfo
import com.google.container.tools.test.ContainerToolsRule
import com.google.container.tools.test.TestService
import io.mockk.impl.annotations.MockK
import org.junit.Rule
import org.junit.Test

/**
* Tests for [UsageTrackerProvider].
*/
class UsageTrackerProviderTest {
@get:Rule
val containerToolsRule = ContainerToolsRule(this)

@MockK
@TestService
private lateinit var usageTrackerManagerService: UsageTrackerManagerService

@MockK
@TestService
private lateinit var pluginInfo: PluginInfo

@Test
fun `usage tracker provides initializes usage tracker`() {
Truth.assertThat(UsageTrackerProvider().usageTracker).isNotNull()
}
}
Loading

0 comments on commit 02f411e

Please sign in to comment.