Skip to content

Commit

Permalink
[FAB-11303] Java cc build update
Browse files Browse the repository at this point in the history
Added GenerateDockerBuild in java platform
Restored support for deploing java cc as source
Added support for multiple exclude dirs in WriteFolderToTarPackage
Unit test for java platform updated
TestGenerateDockerBuild disabled until javaenv docker image problem solved

Change-Id: I862d7243348b08c02d0fc2f4fb6e22491a8c1758
Signed-off-by: gennady <gennady@il.ibm.com>
  • Loading branch information
gennadylaventman committed Aug 14, 2018
1 parent cb33d95 commit b766b28
Show file tree
Hide file tree
Showing 15 changed files with 208 additions and 111 deletions.
117 changes: 77 additions & 40 deletions core/chaincode/platforms/java/java_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,32 +10,30 @@ import (
"archive/tar"
"bytes"
"compress/gzip"
"testing"

"strings"

"io/ioutil"
"fmt"
"os"
"strings"
"testing"

"github.com/hyperledger/fabric/core/chaincode/platforms"
"github.com/hyperledger/fabric/core/chaincode/platforms/java"
"github.com/hyperledger/fabric/core/config/configtest"
"github.com/hyperledger/fabric/core/container/util"
pb "github.com/hyperledger/fabric/protos/peer"
"github.com/spf13/viper"
"github.com/stretchr/testify/assert"
)

var _ = platforms.Platform(&java.Platform{})

const chaincodePathFolder = "testdata"
const chaincodePath = chaincodePathFolder + "/chaincode.jar"

const expected = `
ADD codepackage.tgz /root/chaincode-java/chaincode`
const chaincodePathFolderGradle = chaincodePathFolder + "/gradle"

var spec = &pb.ChaincodeSpec{
Type: pb.ChaincodeSpec_JAVA,
ChaincodeId: &pb.ChaincodeID{
Name: "ssample",
Path: chaincodePath},
Path: chaincodePathFolderGradle},
Input: &pb.ChaincodeInput{
Args: [][]byte{[]byte("f")}}}

Expand All @@ -49,20 +47,20 @@ func TestValidatePath(t *testing.T) {
func TestGetDeploymentPayload(t *testing.T) {
platform := java.Platform{}

_, err := platform.GetDeploymentPayload("pathdoesnotexist")
assert.Contains(t, err.Error(), "no such file or directory")
_, err := platform.GetDeploymentPayload("")
assert.Contains(t, err.Error(), "ChaincodeSpec's path cannot be empty")

spec.ChaincodeId.Path = chaincodePath
_, err = os.Stat(chaincodePath)
if os.IsNotExist(err) {
createTestJar(t)
defer os.RemoveAll(chaincodePathFolder)
}
spec.ChaincodeId.Path = chaincodePathFolderGradle

payload, err := platform.GetDeploymentPayload(chaincodePath)
payload, err := platform.GetDeploymentPayload(chaincodePathFolderGradle)
assert.NoError(t, err)
assert.NotZero(t, len(payload))

buildFileFound := false
settingsFileFound := false
pomFileFound := false
srcFileFound := false

is := bytes.NewReader(payload)
gr, err := gzip.NewReader(is)
if err != nil {
Expand All @@ -78,49 +76,88 @@ func TestGetDeploymentPayload(t *testing.T) {
break
}

if strings.Contains(header.Name, "chaincode.jar") {
return
if strings.Contains(header.Name, ".class") {
assert.Fail(t, "Result package can't contain class file")
}
if strings.Contains(header.Name, "target/") {
assert.Fail(t, "Result package can't contain target folder")
}
if strings.Contains(header.Name, "build/") {
assert.Fail(t, "Result package can't contain build folder")
}
if strings.Contains(header.Name, "src/build.gradle") {
buildFileFound = true
}
if strings.Contains(header.Name, "src/settings.gradle") {
settingsFileFound = true
}
if strings.Contains(header.Name, "src/pom.xml") {
pomFileFound = true
}
if strings.Contains(header.Name, "src/main/java/example/ExampleCC.java") {
srcFileFound = true
}
}
assert.NoError(t, err, "Error while looking for jar in tar file")
assert.Fail(t, "Didn't find expected jar")

assert.True(t, buildFileFound, "Can't find build.gradle file in tar")
assert.True(t, settingsFileFound, "Can't find settings.gradle file in tar")
assert.True(t, pomFileFound, "Can't find pom.xml file in tar")
assert.True(t, srcFileFound, "Can't find example.cc file in tar")
assert.NoError(t, err, "Error while scanning tar file")
}

func TestGenerateDockerfile(t *testing.T) {
platform := java.Platform{}

spec.ChaincodeId.Path = chaincodePath
_, err := os.Stat(chaincodePath)
if os.IsNotExist(err) {
createTestJar(t)
defer os.RemoveAll(chaincodePathFolder)
}
_, err = platform.GetDeploymentPayload(spec.Path())
spec.ChaincodeId.Path = chaincodePathFolderGradle
_, err := platform.GetDeploymentPayload(spec.Path())
if err != nil {
t.Fatalf("failed to get Java CC payload: %s", err)
}

dockerfile, err := platform.GenerateDockerfile()
assert.NoError(t, err)
assert.Equal(t, expected, dockerfile)

var buf []string

buf = append(buf, "FROM "+util.GetDockerfileFromConfig("chaincode.java.Dockerfile"))
buf = append(buf, "ADD binpackage.tar /root/chaincode-java/chaincode")

dockerFileContents := strings.Join(buf, "\n")

assert.Equal(t, dockerFileContents, dockerfile)
}

func TestGenerateDockerBuild(t *testing.T) {
t.Skip("Will re-enable once fabric-chaincode-java CI will produce and publish javaenv docker image")
platform := java.Platform{}
ccSpec := &pb.ChaincodeSpec{
Type: pb.ChaincodeSpec_JAVA,
ChaincodeId: &pb.ChaincodeID{Path: chaincodePathFolderGradle},
Input: &pb.ChaincodeInput{Args: [][]byte{[]byte("init")}}}

cp, _ := platform.GetDeploymentPayload(ccSpec.Path())

cds := &pb.ChaincodeDeploymentSpec{
CodePackage: []byte{}}
tw := tar.NewWriter(gzip.NewWriter(bytes.NewBuffer(nil)))
ChaincodeSpec: ccSpec,
CodePackage: cp}

payload := bytes.NewBuffer(nil)
gw := gzip.NewWriter(payload)
tw := tar.NewWriter(gw)

err := platform.GenerateDockerBuild(cds.Path(), cds.Bytes(), tw)
assert.NoError(t, err)
}

func createTestJar(t *testing.T) {
os.MkdirAll(chaincodePathFolder, 0755)
// No need for real jar at this point, so any binary file will work
err := ioutil.WriteFile(chaincodePath, []byte("Hello, world"), 0644)
if err != nil {
assert.Fail(t, "Can't create test jar file", err.Error())
func TestMain(m *testing.M) {
viper.SetConfigName("core")
viper.SetEnvPrefix("CORE")
configtest.AddDevConfigPath(nil)
viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
viper.AutomaticEnv()
if err := viper.ReadInConfig(); err != nil {
fmt.Printf("could not read config %s\n", err)
os.Exit(-1)
}
os.Exit(m.Run())
}
39 changes: 0 additions & 39 deletions core/chaincode/platforms/java/package.go

This file was deleted.

59 changes: 47 additions & 12 deletions core/chaincode/platforms/java/platform.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,21 @@ import (
"archive/tar"
"bytes"
"compress/gzip"
"errors"
"fmt"
"net/url"
"strings"

"github.com/hyperledger/fabric/common/flogging"
"github.com/hyperledger/fabric/core/chaincode/platforms"
"github.com/hyperledger/fabric/core/chaincode/platforms/ccmetadata"
"github.com/hyperledger/fabric/core/chaincode/platforms/util"
cutil "github.com/hyperledger/fabric/core/container/util"
pb "github.com/hyperledger/fabric/protos/peer"
)

var logger = flogging.MustGetLogger("java-platform")

// Platform for java chaincodes in java
type Platform struct {
}
Expand All @@ -32,6 +37,7 @@ func (javaPlatform *Platform) Name() string {
func (javaPlatform *Platform) ValidatePath(rawPath string) error {
path, err := url.Parse(rawPath)
if err != nil || path == nil {
logger.Errorf("invalid chaincode path %s %v", rawPath, err)
return fmt.Errorf("invalid path: %s", err)
}

Expand All @@ -46,39 +52,68 @@ func (javaPlatform *Platform) ValidateCodePackage(code []byte) error {
// WritePackage writes the java chaincode package
func (javaPlatform *Platform) GetDeploymentPayload(path string) ([]byte, error) {

logger.Debugf("Packaging java project from path %s", path)
var err error

inputbuf := bytes.NewBuffer(nil)
gw := gzip.NewWriter(inputbuf)
// --------------------------------------------------------------------------------------
// Write out our tar package
// --------------------------------------------------------------------------------------
payload := bytes.NewBuffer(nil)
gw := gzip.NewWriter(payload)
tw := tar.NewWriter(gw)

err = writeChaincodePackage(path, tw)
folder := path
if folder == "" {
logger.Error("ChaincodeSpec's path cannot be empty")
return nil, errors.New("ChaincodeSpec's path cannot be empty")
}

tw.Close()
gw.Close()
// trim trailing slash if it exists
if folder[len(folder)-1] == '/' {
folder = folder[:len(folder)-1]
}

if err != nil {
return nil, err
if err = cutil.WriteJavaProjectToPackage(tw, folder); err != nil {

logger.Errorf("Error writing java project to tar package %s", err)
return nil, fmt.Errorf("Error writing Chaincode package contents: %s", err)
}

payload := inputbuf.Bytes()
tw.Close()
gw.Close()

return payload, nil
return payload.Bytes(), nil
}

func (javaPlatform *Platform) GenerateDockerfile() (string, error) {
var buf []string

buf = append(buf, cutil.GetDockerfileFromConfig("chaincode.java.Dockerfile"))
buf = append(buf, "ADD codepackage.tgz /root/chaincode-java/chaincode")
buf = append(buf, "FROM "+cutil.GetDockerfileFromConfig("chaincode.java.Dockerfile"))
buf = append(buf, "ADD binpackage.tar /root/chaincode-java/chaincode")

dockerFileContents := strings.Join(buf, "\n")

return dockerFileContents, nil
}

func (javaPlatform *Platform) GenerateDockerBuild(path string, code []byte, tw *tar.Writer) error {
return cutil.WriteBytesToPackage("codepackage.tgz", code, tw)
codepackage := bytes.NewReader(code)
binpackage := bytes.NewBuffer(nil)
buildOptions := util.DockerBuildOptions{
Image: cutil.GetDockerfileFromConfig("chaincode.java.Dockerfile"),
Cmd: "./build.sh",
InputStream: codepackage,
OutputStream: binpackage,
}
logger.Debugf("Executing docker build %v, %v", buildOptions.Image, buildOptions.Cmd)
err := util.DockerBuild(buildOptions)
if err != nil {
logger.Errorf("Can't build java chaincode %v", err)
return err
}

resultBytes := binpackage.Bytes()
return cutil.WriteBytesToPackage("binpackage.tar", resultBytes, tw)
}

//GetMetadataProvider fetches metadata provider given deployment spec
Expand Down
29 changes: 29 additions & 0 deletions core/chaincode/platforms/java/testdata/gradle/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
plugins {
id 'com.github.johnrengelman.shadow' version '2.0.3'
id 'java'
}

group 'org.hyperledger.fabric'
version '1.0-SNAPSHOT'

sourceCompatibility = 1.8

repositories {
mavenLocal()
mavenCentral()
}

dependencies {
compile group: 'org.hyperledger.fabric', name: 'fabric-chaincode-shim', version: '1.2.0-SNAPSHOT'
testCompile group: 'junit', name: 'junit', version: '4.12'
}

shadowJar {
baseName = 'chaincode'
version = null
classifier = null

manifest {
attributes 'Main-Class': 'example.ExampleCC'
}
}
1 change: 1 addition & 0 deletions core/chaincode/platforms/java/testdata/gradle/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
test maven build file
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
rootProject.name = 'fabric-chaincode-example-gradle'
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package example;

import io.netty.handler.ssl.OpenSsl;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hyperledger.fabric.shim.ChaincodeBase;

public class ExampleCC extends ChaincodeBase {

private static Log _logger = LogFactory.getLog(ExampleCC.class);

@Override
public Response init(ChaincodeStub stub) {
_logger.info("Init java simple chaincode");
return newSuccessResponse();
}

@Override
public Response invoke(ChaincodeStub stub) {
_logger.info("Invoke java simple chaincode");
return newSuccessResponse();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
test class file
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
test class file in target folder
Loading

0 comments on commit b766b28

Please sign in to comment.