Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature files can not read from Spring boot structure. Feature files in source folder not in test folder #1320

Closed
MaghizMannan2108 opened this issue Feb 9, 2018 · 12 comments

Comments

@MaghizMannan2108
Copy link

MaghizMannan2108 commented Feb 9, 2018

Summary

Please note your using all the classes with final variable. Those variable used in public methods. because of that we can not override your public methods.

Spring Boot is archive different way. So we can not find the cucumber feature file inside the source folder.

Expected Behavior

when your using public method in a class, use only constructor variables. don't re-modify something and use inside a public method. Because we can not override your methods. if override we can not re-assign variable values inside those methods.

Current Behavior

our requirement is we have to keep the feature files inside the source. So we create a archive with structure of spring boot means we can not read those feature files.

Possible Solution

one way you have to allow to override and use your existing public method
or
you have to give all the features in your jar (This is not possible. Because feature nobody knows)

Steps to Reproduce (for bugs)

  1. just source folder keep the feature files and java class files.
  2. pack as a spring boot structure
  3. try to read feature files
  4. you come to know

Your Environment

any environment

@mlvandijk
Copy link
Member

mlvandijk commented Feb 14, 2018

@MaghizMannan We use Spring Boot with Cucumber at work for one of our latest projects without any problems.

To help us reproduce your issue, could you please provide additional information:

  • Spring Boot version
  • Cucumber version
  • Build tools (if any) or pom.xml or build file if Maven/Gradle
  • OS
  • Structure of your project
  • How you are running your tests

Or, if you're able to provide a Minimal, Complete, and Verifiable example, that would be even better :)

@MaghizMannan2108
Copy link
Author

Sorry for delay response.
Spring Boot packed with SpringBootProj.jar!/Boot-INF/classes!/com.
but normally java packed with JAVAProj.jar!/com.

So isFactoryFor method only looking !/ and createIterator method path variable only taking com. packages in class ZipResourceIteratorFactory.
but Spring boot path variable value Boot-INF/classes/com.

so when i packed Spring boot it goes to ZipResourceIteratorFactory and does not taking feature file in Spring boot structure package.

If you are not getting, please let me know your understanding of my issue.

Thank you very much for your response for my importance

@aslakhellesoy
Copy link
Contributor

Please provide a minimal, complete and verifiable example

@mpkorstanje
Copy link
Contributor

@MaghizMannan this is a public issue tracker. And please follow the instructions for creating an mcve.

@MaghizMannan2108
Copy link
Author

MaghizMannan2108 commented Feb 19, 2018

I will do and open later

@MaghizMannan2108
Copy link
Author

MaghizMannan2108 commented Feb 21, 2018

featurefile.zip

My test cases are not in test folder. Those test cases are in main folder. this is our requirement to test external system.

This is very simple maven spring boot application. it is just call the feature file via karate. if you include the project in intellj means it will work perfectly. but if you create a jar and run means it will throw the error like no feature file found.

cd D:\Public\test\featurefile
mvn clean install
cd target
java -jar featurefile-0.0.1-SNAPSHOT.jar

I can not get clear idea mcve. please send me as one sample link, I will follow as that.

@MaghizMannan2108 MaghizMannan2108 changed the title Feature files can not read from Spring boot structure. Feature files in source folder not in resource. Feature files can not read from Spring boot structure. Feature files in source folder not in test folder Feb 21, 2018
@mpkorstanje
Copy link
Contributor

Thanks. That actually clears up allot!

SpringBoot uses a nested jar structure that requires the use of ApplicationContext.getResources to access it transparently. As such you'll have to implement a resource loader that utilizes the application context. This might look something like the snippet below. Keep in mind that you'll have to figure out how to provide the path and and relative path.

        ApplicationContext context = SpringApplication.run(FeaturefileApplication.class, args);

        ResourceLoader resourceLoader = (path, suffix) -> {

            try {
                Resource[] resources = context.getResources(path);
                return Arrays.stream(resources)
                        .map(resource -> new cucumber.runtime.io.Resource() {

                            @Override
                            public String getPath() {
                                return null;
                            }

                            @Override
                            public String getAbsolutePath() {
                                return null;
                            }

                            @Override
                            public InputStream getInputStream() throws IOException {
                                return resource.getInputStream();
                            }

                            @Override
                            public String getClassName(String extension) {
                                return null;
                            }
                        }).collect(toList());
            } catch (IOException e) {
                throw new CucumberException(e);
            }
        };

        RuntimeOptionsFactory runtimeOptionsFactory = new RuntimeOptionsFactory(FeatureTest.class);
        RuntimeOptions runtimeOptions = runtimeOptionsFactory.create();
        List<CucumberFeature> cfs = runtimeOptions.cucumberFeatures(resourceLoader);

Unfortunately you are also using Karate which instantiates the Cucumber runtime for you. As such you'll be unable to to provide the context based resource loader to the runtime. You'll have to take this up with the Karate people or instantiate your own runtime.

@noel-yap
Copy link

@schneebuzz
Copy link

Thanks. That actually clears up allot!

SpringBoot uses a nested jar structure that requires the use of ApplicationContext.getResources to access it transparently. As such you'll have to implement a resource loader that utilizes the application context. This might look something like the snippet below. Keep in mind that you'll have to figure out how to provide the path and and relative path.

        ApplicationContext context = SpringApplication.run(FeaturefileApplication.class, args);

        ResourceLoader resourceLoader = (path, suffix) -> {

            try {
                Resource[] resources = context.getResources(path);
                return Arrays.stream(resources)
                        .map(resource -> new cucumber.runtime.io.Resource() {

                            @Override
                            public String getPath() {
                                return null;
                            }

                            @Override
                            public String getAbsolutePath() {
                                return null;
                            }

                            @Override
                            public InputStream getInputStream() throws IOException {
                                return resource.getInputStream();
                            }

                            @Override
                            public String getClassName(String extension) {
                                return null;
                            }
                        }).collect(toList());
            } catch (IOException e) {
                throw new CucumberException(e);
            }
        };

        RuntimeOptionsFactory runtimeOptionsFactory = new RuntimeOptionsFactory(FeatureTest.class);
        RuntimeOptions runtimeOptions = runtimeOptionsFactory.create();
        List<CucumberFeature> cfs = runtimeOptions.cucumberFeatures(resourceLoader);

Unfortunately you are also using Karate which instantiates the Cucumber runtime for you. As such you'll be unable to to provide the context based resource loader to the runtime. You'll have to take this up with the Karate people or instantiate your own runtime.

I know this is somewhat outdated but is there a way to achieve the above in the current version? I'm still struggling to see through the layers since the API changed a bit. Can this be achieved with the new API (to load resources using the ApplicationContext in a nested spring jar)? Or is the way to go to implement the feature in io.cucumber.core.resources.JarUriFileSystemService?

@mpkorstanje
Copy link
Contributor

mpkorstanje commented Mar 26, 2020

Since #1821 you should have limited support for executing inside spring boot. It will discover feature files and glue inside BOOT-INF/classes.

You can also use the runtime builder and provide your own source of features. Note though that this is an internal API so breaking changes may occur.

        ApplicationContext context = ...;


        RuntimeOptions runtimeOptions = new RuntimeOptionsBuilder()
            .addDefaultGlueIfAbsent()
            .build();

        FeatureSupplier featureSupplier = new FeatureSupplier() {
            @Override
            public List<Feature> get() {
                FeatureParser featureParser = new FeatureParser(UUID::randomUUID);
                return Arrays.stream(context.getResources("**.feature"))
                    .map(resource -> new Resource() {
                        @Override
                        public URI getUri() {
                            return resource.getURI();
                        }

                        @Override
                        public InputStream getInputStream() throws IOException {
                            return resource.getInputStream();
                        }
                    })
                    .map(featureParser::parseResource)
                    .collect(Collectors.toList());
            }
        };
        
        final Runtime runtime = Runtime.builder()
            .withFeatureSupplier(featureSupplier)
            .withRuntimeOptions(runtimeOptions)
            .build();

        runtime.run();

@schneebuzz
Copy link

Thank you for the useful information!

The same problem arises for the GlueCode. Since cucumber implements its own scanning based on URIs, it seems that it is not enough to pass the ClassLoader of the spring context using withClassLoader() on the Runtime.Builder. Is there a similar workaround for glue classes?

Also is there an issue or plans to add whats missing in the JarUriFileSystemService where one could work on?

@mpkorstanje
Copy link
Contributor

No, no plans. I'd say your options are:

  1. Keep your glue code and features in BOOT-INF/classes
  2. Unpack your jar before execution
  3. Consider launching cucumber from a regular application rather then spring boot.
  4. Propose a new feature.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants