a06f331eb8
CI / benchmark (push) Has been skipped
install-script / posix-syntax (push) Successful in 6m1s
CI / build-onnx (push) Failing after 6m43s
init-smoke / dry-run (push) Failing after 15m57s
security / govulncheck (push) Has been cancelled
security / trivy-fs (push) Has been cancelled
CI / test (1.26, ubuntu-latest) (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
CI / test (1.26, macos-latest) (push) Has been cancelled
CI / build-windows (push) Has been cancelled
CI / lint (push) Has been cancelled
install-script / powershell-syntax (push) Has been cancelled
install-script / install (macos-14) (push) Has been cancelled
install-script / install (ubuntu-latest) (push) Has been cancelled
171 lines
4.9 KiB
Go
171 lines
4.9 KiB
Go
package indexer
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
"go.uber.org/zap"
|
|
|
|
"github.com/zzet/gortex/internal/config"
|
|
"github.com/zzet/gortex/internal/graph"
|
|
"github.com/zzet/gortex/internal/parser"
|
|
"github.com/zzet/gortex/internal/parser/languages"
|
|
)
|
|
|
|
func TestIndex_SpringDatasourceConditionalOnPropertyReadsConfig(t *testing.T) {
|
|
dir := t.TempDir()
|
|
javaDir := filepath.Join(dir, "src", "main", "java", "com", "example")
|
|
resDir := filepath.Join(dir, "src", "main", "resources")
|
|
require.NoError(t, os.MkdirAll(javaDir, 0o755))
|
|
require.NoError(t, os.MkdirAll(resDir, 0o755))
|
|
|
|
writeFile(t, filepath.Join(javaDir, "JdbcConfig.java"), `
|
|
package com.example;
|
|
|
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
|
import org.springframework.context.annotation.Configuration;
|
|
|
|
@Configuration
|
|
@ConditionalOnProperty(prefix = "spring.datasource", name = "url")
|
|
public class JdbcConfig {
|
|
}
|
|
`)
|
|
writeFile(t, filepath.Join(resDir, "application.yml"), `
|
|
spring:
|
|
datasource:
|
|
url: jdbc:h2:mem:test
|
|
username: sa
|
|
`)
|
|
|
|
g := graph.New()
|
|
reg := parser.NewRegistry()
|
|
languages.RegisterAll(reg)
|
|
idx := New(g, reg, config.Default().Index, zap.NewNop())
|
|
_, err := idx.Index(dir)
|
|
require.NoError(t, err)
|
|
|
|
javaGraphPath := filepath.Join("src", "main", "java", "com", "example", "JdbcConfig.java")
|
|
cfgID := javaGraphPath + "::JdbcConfig"
|
|
keyID := "cfg::spring::spring.datasource.url"
|
|
if g.GetNode(keyID) == nil {
|
|
t.Logf("file nodes: %v", nodeIDsOfKind(g, graph.KindFile))
|
|
t.Logf("config nodes: %v", nodeIDsOfKind(g, graph.KindConfigKey))
|
|
}
|
|
require.NotNil(t, g.GetNode(keyID), "spring.datasource.url config key should be indexed")
|
|
require.True(t, hasEdge(g, cfgID, keyID, graph.EdgeReadsConfig),
|
|
"JdbcConfig should read spring.datasource.url via @ConditionalOnProperty")
|
|
}
|
|
|
|
func TestIndex_SpringExplicitDataSourceBeanLinksToBeanConsumers(t *testing.T) {
|
|
dir := t.TempDir()
|
|
javaDir := filepath.Join(dir, "src", "main", "java", "com", "example")
|
|
require.NoError(t, os.MkdirAll(javaDir, 0o755))
|
|
|
|
writeFile(t, filepath.Join(javaDir, "JdbcConfig.java"), `
|
|
package com.example;
|
|
|
|
import javax.sql.DataSource;
|
|
import org.springframework.context.annotation.Bean;
|
|
import org.springframework.jdbc.core.JdbcTemplate;
|
|
|
|
public class JdbcConfig {
|
|
@Bean
|
|
DataSource dataSource() {
|
|
return null;
|
|
}
|
|
|
|
@Bean
|
|
JdbcTemplate jdbcTemplate(DataSource dataSource) {
|
|
return new JdbcTemplate(dataSource);
|
|
}
|
|
}
|
|
`)
|
|
|
|
g := graph.New()
|
|
reg := parser.NewRegistry()
|
|
languages.RegisterAll(reg)
|
|
idx := New(g, reg, config.Default().Index, zap.NewNop())
|
|
_, err := idx.Index(dir)
|
|
require.NoError(t, err)
|
|
|
|
javaGraphPath := filepath.Join("src", "main", "java", "com", "example", "JdbcConfig.java")
|
|
classID := javaGraphPath + "::JdbcConfig"
|
|
dataSourceID := classID + ".dataSource"
|
|
if !hasEdge(g, classID, dataSourceID, graph.EdgeCalls) {
|
|
t.Logf("calls edges: %v", edgePairsOfKind(g, graph.EdgeCalls))
|
|
t.Logf("provides edges: %v", edgePairsOfKind(g, graph.EdgeProvides))
|
|
}
|
|
require.True(t, hasEdge(g, classID, dataSourceID, graph.EdgeCalls),
|
|
"JdbcConfig should have a spring.Bean edge to the DataSource factory because jdbcTemplate consumes DataSource")
|
|
}
|
|
|
|
func TestIndex_SpringDataSourcePlainMethodDoesNotLinkBeanFactory(t *testing.T) {
|
|
dir := t.TempDir()
|
|
javaDir := filepath.Join(dir, "src", "main", "java", "com", "example")
|
|
require.NoError(t, os.MkdirAll(javaDir, 0o755))
|
|
|
|
writeFile(t, filepath.Join(javaDir, "JdbcConfig.java"), `
|
|
package com.example;
|
|
|
|
import javax.sql.DataSource;
|
|
import org.springframework.context.annotation.Bean;
|
|
|
|
public class JdbcConfig {
|
|
@Bean
|
|
DataSource dataSource() {
|
|
return null;
|
|
}
|
|
|
|
void inspect(DataSource dataSource) {
|
|
}
|
|
}
|
|
`)
|
|
|
|
g := graph.New()
|
|
reg := parser.NewRegistry()
|
|
languages.RegisterAll(reg)
|
|
idx := New(g, reg, config.Default().Index, zap.NewNop())
|
|
_, err := idx.Index(dir)
|
|
require.NoError(t, err)
|
|
|
|
javaGraphPath := filepath.Join("src", "main", "java", "com", "example", "JdbcConfig.java")
|
|
classID := javaGraphPath + "::JdbcConfig"
|
|
dataSourceID := classID + ".dataSource"
|
|
if hasEdge(g, classID, dataSourceID, graph.EdgeCalls) {
|
|
t.Logf("calls edges: %v", edgePairsOfKind(g, graph.EdgeCalls))
|
|
}
|
|
require.False(t, hasEdge(g, classID, dataSourceID, graph.EdgeCalls),
|
|
"a plain method parameter should not make the class look like a Spring bean consumer")
|
|
}
|
|
|
|
func hasEdge(g *graph.Graph, from, to string, kind graph.EdgeKind) bool {
|
|
for _, e := range g.AllEdges() {
|
|
if e.From == from && e.To == to && e.Kind == kind {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func nodeIDsOfKind(g *graph.Graph, kind graph.NodeKind) []string {
|
|
var out []string
|
|
for _, n := range g.AllNodes() {
|
|
if n.Kind == kind {
|
|
out = append(out, n.ID)
|
|
}
|
|
}
|
|
return out
|
|
}
|
|
|
|
func edgePairsOfKind(g *graph.Graph, kind graph.EdgeKind) []string {
|
|
var out []string
|
|
for _, e := range g.AllEdges() {
|
|
if e.Kind == kind {
|
|
out = append(out, e.From+"->"+e.To)
|
|
}
|
|
}
|
|
return out
|
|
}
|