Skip to content

Commit

Permalink
Regression test to certify legacy Ivy publication behavior (#560)
Browse files Browse the repository at this point in the history
Adds a Gradle int test: Grandparent -> parent -> child pattern certifies that child project can transitively resolve references to schemas contained in grandparent's data-template jar.
  • Loading branch information
DPUkyle authored Mar 17, 2021
1 parent cbac36d commit 13c8d24
Show file tree
Hide file tree
Showing 4 changed files with 488 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,270 @@
package com.linkedin.pegasus.gradle.publishing

import org.gradle.testkit.runner.GradleRunner
import org.gradle.testkit.runner.TaskOutcome
import org.junit.Rule
import org.junit.rules.TemporaryFolder
import spock.lang.Specification

import java.util.zip.ZipFile

/**
* Regression test to certify legacy Ivy publication behavior
*
* <p>Grandparent -> parent -> child pattern certifies that the child project can transitively resolve references
* to schemas contained in grandparent's data-template jar
*/
class PegasusPluginLegacyIvyPublishIntegrationTest extends Specification {

@Rule
TemporaryFolder grandparentProject

@Rule
TemporaryFolder parentProject

@Rule
TemporaryFolder childProject

@Rule
TemporaryFolder localRepo

URL localIvyRepo

def setup() {
localIvyRepo = localRepo.newFolder('local-ivy-repo').toURI().toURL()
}

def 'publishes and consumes dataTemplate configurations'() {
given:
def gradlePropertiesFile = grandparentProject.newFile('gradle.properties')
gradlePropertiesFile << '''
|group=com.linkedin.pegasus-grandparent-demo
|version=1.0.0
|'''.stripMargin()

def settingsFile = grandparentProject.newFile('settings.gradle')
settingsFile << "rootProject.name = 'grandparent'"

grandparentProject.newFile('build.gradle') << """
|plugins {
| id 'pegasus'
|}
|
|repositories {
| mavenCentral()
|}
|
|dependencies {
| dataTemplateCompile files(${System.getProperty('integTest.dataTemplateCompileDependencies')})
| pegasusPlugin files(${System.getProperty('integTest.pegasusPluginDependencies')})
|}
|
|//legacy publishing configuration
|tasks.withType(Upload) {
| repositories {
| ivy { url '$localIvyRepo' }
| }
|}""".stripMargin()

// Create a simple pdl schema, borrowed from restli-example-api
def schemaFilename = 'LatLong.pdl'
def grandparentPegasusDir = grandparentProject.newFolder('src', 'main', 'pegasus', 'com', 'linkedin', 'grandparent')
def grandparentPdlFile = new File("$grandparentPegasusDir.path$File.separator$schemaFilename")
grandparentPdlFile << '''namespace com.linkedin.grandparent
|
|record LatLong {
| latitude: optional float
| longitude: optional float
|}'''.stripMargin()

when:
def grandparentRunner = GradleRunner.create()
.withProjectDir(grandparentProject.root)
.withPluginClasspath()
.withArguments('uploadDataTemplate', 'uploadTestDataTemplate', 'uploadAvroSchema', 'uploadTestAvroSchema', 'uploadArchives', '-is')
//.forwardOutput()
//.withDebug(true)

def grandparentResult = grandparentRunner.build()

then:
grandparentResult.task(':compileMainGeneratedDataTemplateJava').outcome == TaskOutcome.SUCCESS
grandparentResult.task(':uploadDataTemplate').outcome == TaskOutcome.SUCCESS
grandparentResult.task(':uploadArchives').outcome == TaskOutcome.SUCCESS

def grandparentProjectIvyDescriptor = new File(localIvyRepo.path, 'com.linkedin.pegasus-grandparent-demo/grandparent/1.0.0/ivy-1.0.0.xml')
grandparentProjectIvyDescriptor.exists()
def grandparentProjectIvyDescriptorContents = grandparentProjectIvyDescriptor.text
def expectedGrandparentContents = new File(Thread.currentThread().contextClassLoader.getResource('ivy/legacy/expectedGrandparentIvyDescriptorContents.txt').toURI()).text
grandparentProjectIvyDescriptorContents.contains expectedGrandparentContents

def grandparentProjectPrimaryArtifact = new File(localIvyRepo.path, 'com.linkedin.pegasus-grandparent-demo/grandparent/1.0.0/grandparent-1.0.0.jar')
grandparentProjectPrimaryArtifact.exists()
def grandparentProjectDataTemplateArtifact = new File(localIvyRepo.path, 'com.linkedin.pegasus-grandparent-demo/grandparent/1.0.0/grandparent-data-template-1.0.0.jar')
grandparentProjectDataTemplateArtifact.exists()

assertZipContains(grandparentProjectDataTemplateArtifact, 'com/linkedin/grandparent/LatLong.class')
assertZipContains(grandparentProjectDataTemplateArtifact, 'pegasus/com/linkedin/grandparent/LatLong.pdl')

when: 'a parent project consumes the grandparent project data-template jar'

gradlePropertiesFile = parentProject.newFile('gradle.properties')
gradlePropertiesFile << '''
|group=com.linkedin.pegasus-parent-demo
|version=1.0.0
|'''.stripMargin()

settingsFile = parentProject.newFile('settings.gradle')
settingsFile << "rootProject.name = 'parent'"

parentProject.newFile('build.gradle') << """
|plugins {
| id 'pegasus'
|}
|
|repositories {
| ivy { url '$localIvyRepo' }
| mavenCentral()
|}
|
|dependencies {
| dataTemplateCompile files(${System.getProperty('integTest.dataTemplateCompileDependencies')})
| pegasusPlugin files(${System.getProperty('integTest.pegasusPluginDependencies')})
|
| dataModel group: 'com.linkedin.pegasus-grandparent-demo', name: 'grandparent', version: '1.0.0', configuration: 'dataTemplate'
|}
|
|//legacy publishing configuration
|tasks.withType(Upload) {
| repositories {
| ivy { url '$localIvyRepo' }
| }
|}""".stripMargin()

// Create a simple pdl schema which references a grandparent type
schemaFilename = 'EXIF.pdl'
def parentPegasusDir = parentProject.newFolder('src', 'main', 'pegasus', 'com', 'linkedin', 'parent')
def parentPdlFile = new File("$parentPegasusDir.path$File.separator$schemaFilename")
parentPdlFile << '''namespace com.linkedin.parent
|
|import com.linkedin.grandparent.LatLong
|
|record EXIF {
| isFlash: optional boolean = true
| location: optional LatLong
|}'''.stripMargin()

def parentRunner = GradleRunner.create()
.withProjectDir(parentProject.root)
.withPluginClasspath()
.withArguments('uploadDataTemplate', 'uploadTestDataTemplate', 'uploadAvroSchema', 'uploadTestAvroSchema', 'uploadArchives', '-is')
//.forwardOutput()
//.withDebug(true)

def parentResult = parentRunner.build()

then:
parentResult.task(':compileMainGeneratedDataTemplateJava').outcome == TaskOutcome.SUCCESS
parentResult.task(':uploadDataTemplate').outcome == TaskOutcome.SUCCESS
parentResult.task(':uploadArchives').outcome == TaskOutcome.SUCCESS

def parentProjectIvyDescriptor = new File(localIvyRepo.path, 'com.linkedin.pegasus-parent-demo/parent/1.0.0/ivy-1.0.0.xml')
parentProjectIvyDescriptor.exists()
def parentProjectIvyDescriptorContents = parentProjectIvyDescriptor.text
def expectedParentContents = new File(Thread.currentThread().contextClassLoader.getResource('ivy/legacy/expectedParentIvyDescriptorContents.txt').toURI()).text
parentProjectIvyDescriptorContents.contains expectedParentContents

def parentProjectPrimaryArtifact = new File(localIvyRepo.path, 'com.linkedin.pegasus-parent-demo/parent/1.0.0/parent-1.0.0.jar')
parentProjectPrimaryArtifact.exists()
def parentProjectDataTemplateArtifact = new File(localIvyRepo.path, 'com.linkedin.pegasus-parent-demo/parent/1.0.0/parent-data-template-1.0.0.jar')
parentProjectDataTemplateArtifact.exists()

assertZipContains(parentProjectDataTemplateArtifact, 'com/linkedin/parent/EXIF.class')
assertZipContains(parentProjectDataTemplateArtifact, 'pegasus/com/linkedin/parent/EXIF.pdl')

when: 'a child project transitively consumes the grandparent project data-template jar'

gradlePropertiesFile = childProject.newFile('gradle.properties')
gradlePropertiesFile << '''
|group=com.linkedin.pegasus-child-demo
|version=1.0.0
|'''.stripMargin()

settingsFile = childProject.newFile('settings.gradle')
settingsFile << "rootProject.name = 'child'"

childProject.newFile('build.gradle') << """
|plugins {
| id 'pegasus'
|}
|
|repositories {
| ivy { url '$localIvyRepo' }
| mavenCentral()
|}
|
|dependencies {
| dataTemplateCompile files(${System.getProperty('integTest.dataTemplateCompileDependencies')})
| pegasusPlugin files(${System.getProperty('integTest.pegasusPluginDependencies')})
|
| dataModel group: 'com.linkedin.pegasus-parent-demo', name: 'parent', version: '1.0.0', configuration: 'dataTemplate'
|}
|
|//legacy publishing configuration
|tasks.withType(Upload) {
| repositories {
| ivy { url '$localIvyRepo' }
| }
|}""".stripMargin()

// Create a simple pdl schema which references parent and grandparent types
schemaFilename = 'Photo.pdl'
def childPegasusDir = childProject.newFolder('src', 'main', 'pegasus', 'com', 'linkedin', 'child')
def childPdlFile = new File("$childPegasusDir.path$File.separator$schemaFilename")
childPdlFile << '''namespace com.linkedin.child
|
|import com.linkedin.grandparent.LatLong
|import com.linkedin.parent.EXIF
|
|record Photo {
| id: long
| urn: string
| title: string
| exif: EXIF
| backupLocation: optional LatLong
|}'''.stripMargin()

def childRunner = GradleRunner.create()
.withProjectDir(childProject.root)
.withPluginClasspath()
.withArguments('uploadDataTemplate', 'uploadTestDataTemplate', 'uploadAvroSchema', 'uploadTestAvroSchema', 'uploadArchives', '-is')
//.forwardOutput()
//.withDebug(true)

def childResult = childRunner.build()

then:
childResult.task(':compileMainGeneratedDataTemplateJava').outcome == TaskOutcome.SUCCESS
childResult.task(':uploadDataTemplate').outcome == TaskOutcome.SUCCESS
childResult.task(':uploadArchives').outcome == TaskOutcome.SUCCESS

def childProjectIvyDescriptor = new File(localIvyRepo.path, 'com.linkedin.pegasus-child-demo/child/1.0.0/ivy-1.0.0.xml')
childProjectIvyDescriptor.exists()
def childProjectIvyDescriptorContents = childProjectIvyDescriptor.text
def expectedChildContents = new File(Thread.currentThread().contextClassLoader.getResource('ivy/legacy/expectedChildIvyDescriptorContents.txt').toURI()).text
childProjectIvyDescriptorContents.contains expectedChildContents

def childProjectPrimaryArtifact = new File(localIvyRepo.path, 'com.linkedin.pegasus-child-demo/child/1.0.0/child-1.0.0.jar')
childProjectPrimaryArtifact.exists()
def childProjectDataTemplateArtifact = new File(localIvyRepo.path, 'com.linkedin.pegasus-child-demo/child/1.0.0/child-data-template-1.0.0.jar')
childProjectDataTemplateArtifact.exists()

assertZipContains(childProjectDataTemplateArtifact, 'com/linkedin/child/Photo.class')
assertZipContains(childProjectDataTemplateArtifact, 'pegasus/com/linkedin/child/Photo.pdl')
}

private static boolean assertZipContains(File zip, String path) {
return new ZipFile(zip).getEntry(path)
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<configurations>
<conf name="annotationProcessor" visibility="private"/>
<conf name="apiElements" visibility="private" extends="runtime"/>
<conf name="archives" visibility="public"/>
<conf name="avroSchema" visibility="public"/>
<conf name="avroSchemaGenerator" visibility="private"/>
<conf name="compile" visibility="private" extends="dataModel,dataTemplateCompile"/>
<conf name="compileClasspath" visibility="private" extends="compileOnly,implementation"/>
<conf name="compileOnly" visibility="private"/>
<conf name="dataModel" visibility="public"/>
<conf name="dataTemplate" visibility="public" extends="dataModel,dataTemplateCompile"/>
<conf name="dataTemplateCompile" visibility="private"/>
<conf name="dataTemplateGenerator" visibility="private"/>
<conf name="default" visibility="public" extends="runtimeElements"/>
<conf name="generatedJavadoc" visibility="public"/>
<conf name="generatedSources" visibility="public"/>
<conf name="implementation" visibility="private" extends="compile"/>
<conf name="mainGeneratedDataTemplateAnnotationProcessor" visibility="private"/>
<conf name="mainGeneratedDataTemplateCompile" visibility="private"/>
<conf name="mainGeneratedDataTemplateCompileClasspath" visibility="private" extends="mainGeneratedDataTemplateCompileOnly,mainGeneratedDataTemplateImplementation"/>
<conf name="mainGeneratedDataTemplateCompileOnly" visibility="private"/>
<conf name="mainGeneratedDataTemplateImplementation" visibility="private" extends="mainGeneratedDataTemplateCompile"/>
<conf name="mainGeneratedDataTemplateRuntime" visibility="private" extends="mainGeneratedDataTemplateCompile"/>
<conf name="mainGeneratedDataTemplateRuntimeClasspath" visibility="private" extends="mainGeneratedDataTemplateImplementation,mainGeneratedDataTemplateRuntime,mainGeneratedDataTemplateRuntimeOnly"/>
<conf name="mainGeneratedDataTemplateRuntimeOnly" visibility="private"/>
<conf name="pegasusPlugin" visibility="public"/>
<conf name="restClient" visibility="public" extends="dataTemplate,restClientCompile"/>
<conf name="restClientCompile" visibility="private"/>
<conf name="restModel" visibility="public"/>
<conf name="restTools" visibility="private"/>
<conf name="runtime" visibility="private" extends="compile"/>
<conf name="runtimeClasspath" visibility="private" extends="implementation,runtime,runtimeOnly"/>
<conf name="runtimeElements" visibility="private" extends="implementation,runtime,runtimeOnly"/>
<conf name="runtimeOnly" visibility="private"/>
<conf name="schemaAnnotationHandler" visibility="public"/>
<conf name="testAnnotationProcessor" visibility="private"/>
<conf name="testAvroSchema" visibility="public" extends="avroSchema"/>
<conf name="testCompile" visibility="private" extends="compile,dataTemplateCompile,testDataModel"/>
<conf name="testCompileClasspath" visibility="private" extends="testCompileOnly,testImplementation"/>
<conf name="testCompileOnly" visibility="private"/>
<conf name="testDataModel" visibility="public" extends="dataModel"/>
<conf name="testDataTemplate" visibility="public" extends="dataTemplate,testDataModel"/>
<conf name="testGeneratedDataTemplateAnnotationProcessor" visibility="private"/>
<conf name="testGeneratedDataTemplateCompile" visibility="private"/>
<conf name="testGeneratedDataTemplateCompileClasspath" visibility="private" extends="testGeneratedDataTemplateCompileOnly,testGeneratedDataTemplateImplementation"/>
<conf name="testGeneratedDataTemplateCompileOnly" visibility="private"/>
<conf name="testGeneratedDataTemplateImplementation" visibility="private" extends="testGeneratedDataTemplateCompile"/>
<conf name="testGeneratedDataTemplateRuntime" visibility="private" extends="testGeneratedDataTemplateCompile"/>
<conf name="testGeneratedDataTemplateRuntimeClasspath" visibility="private" extends="testGeneratedDataTemplateImplementation,testGeneratedDataTemplateRuntime,testGeneratedDataTemplateRuntimeOnly"/>
<conf name="testGeneratedDataTemplateRuntimeOnly" visibility="private"/>
<conf name="testGeneratedJavadoc" visibility="public" extends="generatedJavadoc"/>
<conf name="testGeneratedSources" visibility="public" extends="generatedSources"/>
<conf name="testImplementation" visibility="private" extends="implementation,testCompile"/>
<conf name="testRestClient" visibility="public" extends="restClient,testDataTemplate"/>
<conf name="testRestModel" visibility="public" extends="restModel"/>
<conf name="testRuntime" visibility="private" extends="runtime,testCompile"/>
<conf name="testRuntimeClasspath" visibility="private" extends="testImplementation,testRuntime,testRuntimeOnly"/>
<conf name="testRuntimeOnly" visibility="private" extends="runtimeOnly"/>
</configurations>
<publications>
<artifact name="child" type="jar" ext="jar" conf="apiElements,archives,runtime,runtimeElements"/>
<artifact name="child-avro-schema" type="jar" ext="jar" conf="avroSchema"/>
<artifact name="child-data-template" type="jar" ext="jar" conf="dataTemplate"/>
<artifact name="child" type="jar" ext="jar" conf="generatedJavadoc" m:classifier="javadoc"/>
<artifact name="child" type="jar" ext="jar" conf="generatedSources" m:classifier="sources"/>
<artifact name="child-test-avro-schema" type="jar" ext="jar" conf="testAvroSchema"/>
<artifact name="child-test-data-template" type="jar" ext="jar" conf="testDataTemplate"/>
</publications>
<dependencies>
<dependency org="com.linkedin.pegasus-parent-demo" name="parent" rev="1.0.0" conf="dataModel-&gt;dataTemplate"/>
<dependency org="com.google.code.findbugs" name="jsr305" rev="3.0.2" conf="dataTemplateCompile-&gt;default"/>
<dependency org="org.slf4j" name="slf4j-simple" rev="1.7.2" conf="pegasusPlugin-&gt;default"/>
</dependencies>
Loading

0 comments on commit 13c8d24

Please sign in to comment.