Tests unitaires Cloud Storage (2e génération)

Exemple de test unitaire pour une fonction déclenchée par Cloud Storage qui s'exécute dans Cloud Functions (2e génération).

Exemple de code

C#

Pour vous authentifier auprès de Cloud Run Functions, configurez le service Identifiants par défaut de l'application. Pour en savoir plus, consultez Configurer l'authentification pour un environnement de développement local.

using CloudNative.CloudEvents;
using Google.Cloud.Functions.Testing;
using Google.Events;
using Google.Events.Protobuf.Cloud.Storage.V1;
using Microsoft.Extensions.Logging;
using System;
using System.Threading;
using System.Threading.Tasks;
using Xunit;

namespace HelloWorld.Tests;

public class HelloGcsUnitTest
{
    [Fact]
    public async Task FileNameIsLogged()
    {
        // Prepare the inputs
        var data = new StorageObjectData { Name = "new-file.txt" };
        var cloudEvent = new CloudEvent
        {
            Type = StorageObjectData.FinalizedCloudEventType,
            Source = new Uri("//storage.googleapis.com", UriKind.RelativeOrAbsolute),
            Id = "1234",
            Data = data
        };
        var logger = new MemoryLogger<HelloGcs.Function>();

        // Execute the function
        var function = new HelloGcs.Function(logger);
        await function.HandleAsync(cloudEvent, data, CancellationToken.None);

        // Check the log results - just the entry starting with "File:".
        var logEntry = Assert.Single(logger.ListLogEntries(), entry => entry.Message.StartsWith("File:"));
        Assert.Equal("File: new-file.txt", logEntry.Message);
        Assert.Equal(LogLevel.Information, logEntry.Level);
    }
}

Go

Pour vous authentifier auprès de Cloud Run Functions, configurez le service Identifiants par défaut de l'application. Pour en savoir plus, consultez Configurer l'authentification pour un environnement de développement local.


package helloworld

import (
	"context"
	"io"
	"log"
	"os"
	"strings"
	"testing"
	"time"

	"github.com/cloudevents/sdk-go/v2/event"
	"github.com/googleapis/google-cloudevents-go/cloud/storagedata"
	"google.golang.org/protobuf/encoding/protojson"
	"google.golang.org/protobuf/types/known/timestamppb"
)

func TestHelloStorage(t *testing.T) {
	r, w, _ := os.Pipe()
	log.SetOutput(w)
	originalFlags := log.Flags()
	log.SetFlags(log.Flags() &^ (log.Ldate | log.Ltime))

	d := &storagedata.StorageObjectData{
		Name:        "hello_gcs.txt",
		TimeCreated: timestamppb.New(time.Now()),
	}

	jsonData, err := protojson.Marshal(d)
	if err != nil {
		t.Fatalf("protojson.Marshal: %v", err)
	}

	e := event.New()
	e.SetDataContentType("application/json")
	e.SetData(e.DataContentType(), jsonData)

	helloStorage(context.Background(), e)

	w.Close()
	log.SetOutput(os.Stderr)
	log.SetFlags(originalFlags)

	out, err := io.ReadAll(r)
	if err != nil {
		t.Fatalf("ReadAll: %v", err)
	}
	got := string(out)
	if want := d.Name; strings.Contains(want, got) {
		t.Errorf("HelloStorage = %q, want to contain %q", got, want)
	}
	if want := d.TimeCreated.String(); strings.Contains(want, got) {
		t.Errorf("HelloStorage = %q, want to contain %q", got, want)
	}
}

Java

Pour vous authentifier auprès de Cloud Run Functions, configurez le service Identifiants par défaut de l'application. Pour en savoir plus, consultez Configurer l'authentification pour un environnement de développement local.


import static com.google.common.truth.Truth.assertThat;

import com.google.common.testing.TestLogHandler;
import com.google.events.cloud.storage.v1.StorageObjectData;
import com.google.protobuf.InvalidProtocolBufferException;
import com.google.protobuf.Timestamp;
import com.google.protobuf.util.JsonFormat;
import io.cloudevents.CloudEvent;
import io.cloudevents.core.builder.CloudEventBuilder;
import java.net.URI;
import java.util.logging.Logger;
import org.junit.After;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

/** Unit tests for main.java.com.example.functions.helloworld.HelloGcs. */
@RunWith(JUnit4.class)
public class HelloGcsTest {
  private static final TestLogHandler LOG_HANDLER = new TestLogHandler();
  private static final Logger logger = Logger.getLogger(HelloGcs.class.getName());

  @BeforeClass
  public static void beforeClass() throws Exception {
    logger.addHandler(LOG_HANDLER);
  }

  @After
  public void afterTest() {
    LOG_HANDLER.clear();
  }

  @Test
  public void helloGcs_shouldPrintFileName() throws InvalidProtocolBufferException {
    // Create event data
    String file = "foo.txt";
    String bucket = "gs://test-bucket";

    // Get the current time in milliseconds
    long millis = System.currentTimeMillis();

    // Create a Timestamp object
    Timestamp timestamp = Timestamp.newBuilder()
        .setSeconds(millis / 1000)
        .setNanos((int) ((millis % 1000) * 1000000))
        .build();

    StorageObjectData.Builder dataBuilder = StorageObjectData.newBuilder()
        .setName(file)
        .setBucket(bucket)
        .setMetageneration(10)
        .setTimeCreated(timestamp)
        .setUpdated(timestamp);

    String jsonData = JsonFormat.printer().print(dataBuilder);

    // Construct a CloudEvent
    CloudEvent event = CloudEventBuilder.v1()
        .withId("0")
        .withType("google.storage.object.finalize")
        .withSource(URI.create("https://example.com"))
        .withData("application/json", jsonData.getBytes())
        .build();

    new HelloGcs().accept(event);

    String actualBucket = LOG_HANDLER.getStoredLogRecords().get(2).getMessage();
    String actualFile = LOG_HANDLER.getStoredLogRecords().get(3).getMessage();
    assertThat(actualFile).contains("File: " + file);
    assertThat(actualBucket).contains("Bucket: " + bucket);
  }

  @Test
  public void helloGcs_shouldPrintNotifyIfDataIsNull() throws InvalidProtocolBufferException {
    // Construct a CloudEvent
    CloudEvent event = CloudEventBuilder.v1()
        .withId("0")
        .withType("google.storage.object.finalize")
        .withSource(URI.create("https://example.com"))
        .build();

    new HelloGcs().accept(event);

    String logMessage = LOG_HANDLER.getStoredLogRecords().get(2).getMessage();
    assertThat(logMessage).isEqualTo("No data found in cloud event payload!");
  }
}

Node.js

Pour vous authentifier auprès de Cloud Run Functions, configurez le service Identifiants par défaut de l'application. Pour en savoir plus, consultez Configurer l'authentification pour un environnement de développement local.

const {getFunction} = require('@google-cloud/functions-framework/testing');

describe('functions_cloudevent_storage', () => {
  const assert = require('assert');
  const sinon = require('sinon');
  require('..');

  const stubConsole = function () {
    sinon.stub(console, 'error');
    sinon.stub(console, 'log');
  };

  const restoreConsole = function () {
    console.log.restore();
    console.error.restore();
  };

  beforeEach(stubConsole);
  afterEach(restoreConsole);

  it('helloGCS: should print out event', () => {
    const event = {
      id: '1234',
      type: 'mock-gcs-event',
      data: {
        bucket: 'my-bucket',
        name: 'my-file.txt',
      },
    };

    // Call tested function and verify its behavior
    const helloGCS = getFunction('helloGCS');
    helloGCS(event);

    assert(console.log.calledWith('Event ID: 1234'));
    assert(console.log.calledWith('Event Type: mock-gcs-event'));
    assert(console.log.calledWith('Bucket: my-bucket'));
    assert(console.log.calledWith('File: my-file.txt'));
  });
});

PHP

Pour vous authentifier auprès de Cloud Run Functions, configurez le service Identifiants par défaut de l'application. Pour en savoir plus, consultez Configurer l'authentification pour un environnement de développement local.


namespace Google\Cloud\Samples\Functions\HelloworldStorage\Test;

use CloudEvents\V1\CloudEventImmutable;
use CloudEvents\V1\CloudEventInterface;

use PHPUnit\Framework\TestCase;

/**
 * Class SampleUnitTest.
 *
 * Unit test for 'Helloworld Storage' Cloud Function.
 */
class SampleUnitTest extends TestCase
{
    /**
     * Include the Cloud Function code before running any tests.
     *
     * @see https://phpunit.readthedocs.io/en/latest/fixtures.html
     */
    public static function setUpBeforeClass(): void
    {
        require_once __DIR__ . '/index.php';
    }

    public function dataProvider()
    {
        return [
            [
                'cloudevent' => new CloudEventImmutable(
                    uniqId(), // id
                    'storage.googleapis.com', // source
                    'google.cloud.storage.object.v1.finalized', // type
                    [
                        'bucket' => 'some-bucket',
                        'metageneration' => '1',
                        'name' => 'folder/friendly.txt',
                        'timeCreated' => '2020-04-23T07:38:57.230Z',
                        'updated' => '2020-04-23T07:38:57.230Z',
                    ] // data
                ),
                'statusCode' => '200',
            ],
        ];
    }

    /**
     * @dataProvider dataProvider
     */
    public function testFunction(CloudEventInterface $cloudevent): void
    {
        // Capture function output by overriding the function's logging behavior.
        // The 'LOGGER_OUTPUT' environment variable must be used in your function:
        //
        // $log = fopen(getenv('LOGGER_OUTPUT') ?: 'php://stderr', 'wb');
        // fwrite($log, 'Log Entry');
        putenv('LOGGER_OUTPUT=php://output');
        helloGCS($cloudevent);
        // Provided by PHPUnit\Framework\TestCase.
        $actual = $this->getActualOutput();

        // Test output includes the properties provided in the CloudEvent.
        foreach ($cloudevent->getData() as $property => $value) {
            $this->assertStringContainsString($value, $actual);
        }
        $this->assertStringContainsString($cloudevent->getId(), $actual);
        $this->assertStringContainsString($cloudevent->getType(), $actual);
    }
}

Python

Pour vous authentifier auprès de Cloud Run Functions, configurez le service Identifiants par défaut de l'application. Pour en savoir plus, consultez Configurer l'authentification pour un environnement de développement local.


from cloudevents.http import CloudEvent
import pytest

import main


def test_functions_eventsource_storage(capsys: pytest.LogCaptureFixture) -> None:
    attributes = {
        "id": "5e9f24a",
        "type": "google.cloud.storage.object.v1.finalized",
        "source": "sourceUrlHere",
    }

    data = {
        "bucket": "test_bucket_for_storage",
        "name": "new_blob_uploaded",
        "generation": 1,
        "metageneration": 1,
        "timeCreated": "2021-10-10 00:00:00.000000Z",
        "updated": "2021-11-11 00:00:00.000000Z",
    }

    event = CloudEvent(attributes, data)

    (
        event_id,
        event_type,
        bucket,
        name,
        metageneration,
        timeCreated,
        updated,
    ) = main.hello_gcs(event)

    out, _ = capsys.readouterr()
    assert "5e9f24a" in event_id
    assert "google.cloud.storage.object.v1.finalized" in event_type
    assert "test_bucket_for_storage" in bucket
    assert "new_blob_uploaded" in name
    assert metageneration == 1
    assert "2021-10-10 00:00:00.000000Z" in timeCreated
    assert "2021-11-11 00:00:00.000000Z" in updated

Étape suivante

Pour rechercher et filtrer des exemples de code pour d'autres produits Google Cloud, consultez l'explorateur d'exemples Google Cloud.