-1
public URL generateSignedUrl(
                                 String fileName) {
        Optional<URL> url = Optional.empty();
        try {
            long startTime = System.currentTimeMillis();
            Storage storage = buildService(projectId);

            BlobInfo blobInfo = BlobInfo.newBuilder(BlobId.of(bucketName, fileName)).build();
            url = Optional.of(storage.signUrl(blobInfo, validTime, TimeUnit.MINUTES));
            long endTime = System.currentTimeMillis();
            long diffOfTime = endTime - startTime;
            LOGGER.info("Signed url for filename : {} , time taken : {}", fileName, String.valueOf(diffOfTime));
        } catch (Exception e) {
            LOGGER.info("Error for file:{},error {} ", fileName, e);
            throw new ApplicationException(
                    "Failed to get file :: " + fileName, ErrorCode.FAILED_DUE_TO_BUCKET);
        }

        return url.get();
    }

    private Storage buildService(String googleProjectId) {
        StorageOptions.Builder builder = StorageOptions.newBuilder().setProjectId(googleProjectId);
        // First check credPath property. If null, checks GOOGLE_APPLICATION_CREDENTIALS
        String credPath = //path set from System.getProperty();
        if (credPath.length() > 0)
            try {
             builder.setCredentials(ServiceAccountCredentials.fromStream(new FileInputStream(credPath)));//not able to mock this line
            } catch (Exception e) {
                LOGGER.error("Error while setting GCP credential file", e);
                throw new ApplicationException(
                        "Failed to create storage service ", ErrorCode.FAILED_DUE_TO_BUCKET);
            }
        return builder.build().getService();

Not able to mock line in the code as it requires credential json but i don't wont to provide the private key for the bucket and rather want to mock it for credential. Cannot use powermockito due to restriction

1 Answers1

0

To answer quickly, put your credentials acquisition in a dedicated package-protected method, so you can overwrite it in tests.

Something like this:

private Storage buildService(String googleProjectId) {
    StorageOptions.Builder builder = StorageOptions.newBuilder().setProjectId(googleProjectId);
    builder.setCredentials(obtainCredentials());
    return builder.build().getService();
}

Credentials obtainCredentials() {
    ...
    return credentials;
}

This way you can replace the implementation rather simply:

@Test
void a_relevant_name() {
    var service = new MyService("project 1", "bucket A", 42L) {
        @Override
        Credentials obtainCredentials() {
            return return ServiceAccountCredentials.fromStream(new FileInputStream("test-creds-path"));
        }
    };

    // trigger what you need

    // assert what you expect
}

However it is uncommon to retrieve credentials (and access the file system) at each operation. You would more likely load them once at the object creation (or right after it if you use Spring lifecycle hooks) and use them several times.

Furthermore, what you are trying to do is called an integration test, as what you want to test is the integration between your code and the google storage service.

Such test needs to connect, so it needs to have credentials, even if those are not the same as for production code.

If you do not have any credentials to put there, maybe you should ask yourself, what is it you want to assert with this test.

Loïc Le Doyen
  • 975
  • 7
  • 16
  • i cannot use the json file as it has the private key to connect to gcp bucket. i require mocking for that and as we have removed the powermockito dependency i cannot use that to mock the private method – user4886675 May 04 '23 at 12:32
  • What object are you trying to mock? it is unclear. Either you provide test-specialized credentials (the way I showed above) and test your integration, or you mock the complete `Storage` service, in which case, simply changing the private method to `package-protected` will do. – Loïc Le Doyen May 05 '23 at 13:08